Add dns-stack profile and stable IP prompt
This commit is contained in:
@@ -110,6 +110,13 @@ const firstbootErrorClose = document.getElementById("firstbootErrorClose");
|
||||
const firstbootCopyError = document.getElementById("firstbootCopyError");
|
||||
const firstbootShowRecovery = document.getElementById("firstbootShowRecovery");
|
||||
const firstbootRecovery = document.getElementById("firstbootRecovery");
|
||||
const networkModal = document.getElementById("networkModal");
|
||||
const networkClose = document.getElementById("networkClose");
|
||||
const networkReserveBtn = document.getElementById("networkReserveBtn");
|
||||
const networkStaticBtn = document.getElementById("networkStaticBtn");
|
||||
const networkLaterBtn = document.getElementById("networkLaterBtn");
|
||||
const networkHelpBtn = document.getElementById("networkHelpBtn");
|
||||
const networkProfileHint = document.getElementById("networkProfileHint");
|
||||
const confirmModal = document.getElementById("confirmModal");
|
||||
const confirmTitle = document.getElementById("confirmTitle");
|
||||
const confirmBody = document.getElementById("confirmBody");
|
||||
@@ -172,6 +179,58 @@ const firstbootUI = createFirstbootUI({
|
||||
showToast,
|
||||
});
|
||||
|
||||
const networkState = {
|
||||
shown: false,
|
||||
profile: null,
|
||||
};
|
||||
|
||||
function networkKey(profile) {
|
||||
const id = profile?.id || profile?.name || "profile";
|
||||
return `pikit:network-setup:${id}`;
|
||||
}
|
||||
|
||||
function markNetworkHandled(profile, message) {
|
||||
if (!profile) return;
|
||||
try {
|
||||
localStorage.setItem(networkKey(profile), "done");
|
||||
} catch (err) {
|
||||
// ignore storage failures
|
||||
}
|
||||
if (networkModal) networkModal.classList.add("hidden");
|
||||
networkState.shown = false;
|
||||
if (message) showToast?.(message, "success");
|
||||
}
|
||||
|
||||
function openNetworkModal(profile, force = false) {
|
||||
if (!networkModal) return;
|
||||
if (!profile?.requires_stable_ip && !force) return;
|
||||
if (networkProfileHint) {
|
||||
const name = profile?.name ? `${profile.name} profile` : "This profile";
|
||||
networkProfileHint.textContent = `${name} needs a stable IP address so your devices can always reach DNS.`;
|
||||
}
|
||||
networkModal.classList.remove("hidden");
|
||||
networkState.shown = true;
|
||||
networkState.profile = profile;
|
||||
}
|
||||
|
||||
function shouldShowNetworkPrompt(firstbootData) {
|
||||
if (!firstbootData || firstbootData.state !== "done") return false;
|
||||
const profile = firstbootData.profile || null;
|
||||
if (!profile?.requires_stable_ip) return false;
|
||||
if (networkState.shown) return false;
|
||||
try {
|
||||
return localStorage.getItem(networkKey(profile)) !== "done";
|
||||
} catch (err) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function handleFirstbootStatus(firstbootData) {
|
||||
if (shouldShowNetworkPrompt(firstbootData)) {
|
||||
openNetworkModal(firstbootData.profile);
|
||||
}
|
||||
}
|
||||
|
||||
const statusController = createStatusController({
|
||||
heroStats,
|
||||
servicesGrid,
|
||||
@@ -191,6 +250,7 @@ const statusController = createStatusController({
|
||||
getError: getFirstbootError,
|
||||
ui: firstbootUI,
|
||||
},
|
||||
onFirstbootStatus: handleFirstbootStatus,
|
||||
});
|
||||
const { loadStatus } = statusController;
|
||||
|
||||
@@ -220,6 +280,30 @@ function wireDialogs() {
|
||||
addServiceModal?.addEventListener("click", (e) => {
|
||||
if (e.target === addServiceModal) addServiceModal.classList.add("hidden");
|
||||
});
|
||||
networkModal?.addEventListener("click", (e) => {
|
||||
if (e.target === networkModal) {
|
||||
markNetworkHandled(networkState.profile, "Network setup saved");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function wireNetworkSetup() {
|
||||
networkClose?.addEventListener("click", () => {
|
||||
markNetworkHandled(networkState.profile, "Network setup saved");
|
||||
});
|
||||
networkReserveBtn?.addEventListener("click", () => {
|
||||
markNetworkHandled(networkState.profile, "Router reservation saved");
|
||||
});
|
||||
networkStaticBtn?.addEventListener("click", () => {
|
||||
markNetworkHandled(networkState.profile, "Static IP reminder saved");
|
||||
});
|
||||
networkLaterBtn?.addEventListener("click", () => {
|
||||
markNetworkHandled(networkState.profile, "Network setup saved");
|
||||
});
|
||||
networkHelpBtn?.addEventListener("click", () => {
|
||||
if (helpModal) helpModal.classList.add("hidden");
|
||||
openNetworkModal(networkState.profile || { requires_stable_ip: true }, true);
|
||||
});
|
||||
}
|
||||
|
||||
// Testing hook
|
||||
@@ -348,6 +432,7 @@ function main() {
|
||||
window.__pikitTest.exposeServiceForm?.();
|
||||
}
|
||||
wireDialogs();
|
||||
wireNetworkSetup();
|
||||
wireResetAndUpdates();
|
||||
wireAccordions({
|
||||
forceOpen: typeof window !== "undefined" && window.__pikitTest?.forceAccordionsOpen,
|
||||
|
||||
@@ -18,6 +18,7 @@ export function createStatusController({
|
||||
setUpdatesUI = null,
|
||||
updatesFlagEl = null,
|
||||
firstboot = null,
|
||||
onFirstbootStatus = null,
|
||||
}) {
|
||||
let lastStatusData = null;
|
||||
let lastFirstbootState = null;
|
||||
@@ -88,6 +89,7 @@ export function createStatusController({
|
||||
firstbootData = await firstboot.getStatus();
|
||||
lastFirstbootState = firstbootData?.state || lastFirstbootState;
|
||||
firstboot.ui.update(firstbootData);
|
||||
onFirstbootStatus?.(firstbootData);
|
||||
if (firstbootData?.state === "error" && firstboot.getError) {
|
||||
const err = await firstboot.getError();
|
||||
if (err?.present) {
|
||||
|
||||
@@ -132,6 +132,42 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="networkModal" class="modal hidden">
|
||||
<div class="modal-card wide">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<p class="eyebrow">Network setup</p>
|
||||
<h3>Keep DNS reliable</h3>
|
||||
<p class="hint" id="networkProfileHint">
|
||||
This profile needs a stable IP address so your devices can always reach DNS.
|
||||
</p>
|
||||
</div>
|
||||
<button id="networkClose" class="ghost icon-btn close-btn" title="Close network setup">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="help-body">
|
||||
<p>
|
||||
The easiest option is a router reservation. It keeps the Pi on the same IP without
|
||||
changing anything on the Pi itself.
|
||||
</p>
|
||||
<ol>
|
||||
<li>Open your router’s admin page (often <code>http://192.168.0.1</code> or <code>http://10.0.0.1</code>).</li>
|
||||
<li>Find <strong>DHCP reservations</strong> or <strong>Static leases</strong>.</li>
|
||||
<li>Reserve the Pi’s current IP and MAC address.</li>
|
||||
</ol>
|
||||
<div class="control-actions wrap gap">
|
||||
<button id="networkReserveBtn">I set a router reservation</button>
|
||||
<button id="networkStaticBtn" class="ghost">I’ll set a static IP on the Pi</button>
|
||||
<button id="networkLaterBtn" class="ghost">I’ll do this later</button>
|
||||
</div>
|
||||
<p class="hint">
|
||||
You can reopen this from <strong>Help → Network setup</strong> at any time.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="changelogModal" class="modal hidden">
|
||||
<div class="modal-card wide">
|
||||
<div class="panel-header sticky">
|
||||
@@ -726,6 +762,14 @@
|
||||
<li>Factory reset reverts passwords and firewall rules and reboots. Use only when you need a clean slate.</li>
|
||||
</ul>
|
||||
|
||||
<h4>Network setup (DNS profiles)</h4>
|
||||
<ul>
|
||||
<li>DNS profiles work best with a stable IP (router reservation or static IP).</li>
|
||||
<li>
|
||||
<button id="networkHelpBtn" class="ghost">Open network setup</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Troubleshooting</h4>
|
||||
<ul>
|
||||
<li>Service link fails? Make sure the service runs, port/path are right, and edit via the “…” menu.</li>
|
||||
|
||||
Reference in New Issue
Block a user