updated webinterface with modals for station/ap config. landing page. network overview if config is present
This commit is contained in:
parent
7a3e2830a0
commit
fb9f9284a4
4 changed files with 43 additions and 141 deletions
|
|
@ -1,8 +1,3 @@
|
|||
---
|
||||
import IconEye from "../icons/IconEye.astro";
|
||||
import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
||||
---
|
||||
|
||||
<dialog id="ap-config-modal" class="modal modal-middle">
|
||||
<div class="modal-box w-11/12 sm:w-6/12 max-w-5xl flex flex-col">
|
||||
<h1 class="text-lg font-bold">Access Point Configuration</h1>
|
||||
|
|
@ -29,12 +24,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
<input type="password" class="w-full border-none outline-none bg-transparent" id="ap-password" placeholder="Leave empty for open network" />
|
||||
</label>
|
||||
<button type="button" id="toggle-ap-password-btn" class="absolute right-3 top-1/2 -translate-y-1/2 btn btn-ghost btn-xs p-1 min-h-0 h-7 hover:bg-primary hover:text-primary-content">
|
||||
<span id="ap-eye-icon-open">
|
||||
<IconEye size={20} class="opacity-70 hover:opacity-100" />
|
||||
</span>
|
||||
<span id="ap-eye-icon-closed" class="hidden">
|
||||
<IconEyeClosed size={20} class="opacity-70 hover:opacity-100" />
|
||||
</span>
|
||||
<span id="ap-eye-text" class="text-xs opacity-70">show</span>
|
||||
</button>
|
||||
</div>
|
||||
<p id="ap-password-error" class="text-sm text-error hidden"></p>
|
||||
|
|
@ -83,7 +73,8 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
$current_network_configuration,
|
||||
send_new_network_configuration_to_alpha,
|
||||
ConnectionMode,
|
||||
} from "../backend_components/NetworkManagerStore";
|
||||
type NetworkConfigNVS,
|
||||
} from "./NetworkManagerStore";
|
||||
|
||||
const modal = document.getElementById("ap-config-modal") as HTMLDialogElement;
|
||||
const apSSID = document.getElementById("ap-ssid") as HTMLInputElement;
|
||||
|
|
@ -94,8 +85,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
const apPasswordError = document.getElementById("ap-password-error");
|
||||
const apChannel = document.getElementById("ap-channel") as HTMLSelectElement;
|
||||
const toggleApPasswordBtn = document.getElementById("toggle-ap-password-btn");
|
||||
const apEyeOpen = document.getElementById("ap-eye-icon-open");
|
||||
const apEyeClosed = document.getElementById("ap-eye-icon-closed");
|
||||
const apEyeText = document.getElementById("ap-eye-text");
|
||||
|
||||
function resetModal() {
|
||||
if (apSSID) apSSID.value = "";
|
||||
|
|
@ -105,14 +95,15 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
apSSIDError?.classList.add("hidden");
|
||||
apPasswordWrap?.classList.remove("input-error");
|
||||
apPasswordError?.classList.add("hidden");
|
||||
apEyeOpen?.classList.remove("hidden");
|
||||
apEyeClosed?.classList.add("hidden");
|
||||
if (apEyeText) apEyeText.textContent = "show";
|
||||
}
|
||||
|
||||
function prefillFromConfig() {
|
||||
const cfg = $current_network_configuration.get();
|
||||
if (apSSID) apSSID.value = cfg.SSID_AP || "";
|
||||
if (apPassword) apPassword.value = cfg.Password_AP || "";
|
||||
// Password is intentionally blanked by firmware on read — leave the field empty so the
|
||||
// user is forced to re-enter it. Updating it without re-entering would risk wiping it.
|
||||
if (apPassword) apPassword.value = "";
|
||||
if (apChannel) apChannel.value = String(cfg.AP_Channel ?? 0);
|
||||
}
|
||||
|
||||
|
|
@ -132,8 +123,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
if (!apPassword) return;
|
||||
const isVisible = apPassword.type === "text";
|
||||
apPassword.type = isVisible ? "password" : "text";
|
||||
apEyeOpen?.classList.toggle("hidden", !isVisible);
|
||||
apEyeClosed?.classList.toggle("hidden", isVisible);
|
||||
if (apEyeText) apEyeText.textContent = isVisible ? "show" : "hide";
|
||||
});
|
||||
|
||||
apSSID?.addEventListener("input", () => {
|
||||
|
|
@ -175,24 +165,10 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
if (!valid) return;
|
||||
|
||||
const base = $current_network_configuration.get();
|
||||
|
||||
// Derive the APSTA connection mode: keep ETH DHCP/static, switch WiFi to APSTA
|
||||
let apstaMode: ConnectionMode;
|
||||
switch (base.Connection_Mode) {
|
||||
case ConnectionMode.CONNECTION_MODE_ETH_STATIC_NO_WIFI:
|
||||
case ConnectionMode.CONNECTION_MODE_ETH_STATIC_APSTA:
|
||||
case ConnectionMode.CONNECTION_MODE_ETH_STATIC_STA_DHCP:
|
||||
case ConnectionMode.CONNECTION_MODE_ETH_STATIC_STA_STATIC:
|
||||
apstaMode = ConnectionMode.CONNECTION_MODE_ETH_STATIC_APSTA;
|
||||
break;
|
||||
default:
|
||||
apstaMode = ConnectionMode.CONNECTION_MODE_ETH_DHCP_APSTA;
|
||||
}
|
||||
|
||||
const updatedConfig = {
|
||||
// No ethernet in our case — APSTA is always just APSTA mode, no eth-static-vs-dhcp variants.
|
||||
const updatedConfig: NetworkConfigNVS = {
|
||||
...base,
|
||||
Connection_Mode: apstaMode,
|
||||
WiFi_Enabled: true,
|
||||
Connection_Mode: ConnectionMode.CONNECTION_MODE_APSTA,
|
||||
SSID_AP: apSSID.value,
|
||||
Password_AP: apPassword?.value ?? "",
|
||||
AP_Channel: parseInt(apChannel?.value ?? "0", 10),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
---
|
||||
import { IconPlant } from "@tabler/icons-preact";
|
||||
import StationConfigModal from "./StationConfigModal.astro";
|
||||
import AccessPointConfigModal from "./AccessPointConfigModal.astro";
|
||||
---
|
||||
|
||||
<div class="space-y-6">
|
||||
|
|
@ -163,26 +165,14 @@ import { IconPlant } from "@tabler/icons-preact";
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Inline APSTA form (shown when "Access Point" is clicked) -->
|
||||
<div id="apsta-form" class="hidden mt-4 space-y-3 p-4 rounded-lg bg-base-200/50">
|
||||
<h4 class="font-semibold text-sm">Configure Access Point</h4>
|
||||
<label class="form-control">
|
||||
<span class="label-text text-xs">AP SSID</span>
|
||||
<input type="text" id="ov-ap-ssid" maxlength="31" class="input input-bordered input-sm" />
|
||||
</label>
|
||||
<label class="form-control">
|
||||
<span class="label-text text-xs">AP Password (leave blank for open)</span>
|
||||
<input type="text" id="ov-ap-password" maxlength="31" class="input input-bordered input-sm font-mono" />
|
||||
</label>
|
||||
<div class="flex justify-end gap-2">
|
||||
<button id="ov-ap-cancel" class="btn btn-ghost btn-sm">Cancel</button>
|
||||
<button id="ov-ap-apply" class="btn btn-primary btn-sm">Apply AP Mode</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mode-switch modals — opened by the "WiFi Station" / "Access Point" buttons above. -->
|
||||
<StationConfigModal />
|
||||
<AccessPointConfigModal />
|
||||
|
||||
<!-- Network-error dialog (raised when network_config_failed arrives) -->
|
||||
<dialog id="overview-network-error-modal" class="modal modal-middle">
|
||||
<div class="modal-box w-11/12 sm:w-5/12 max-w-lg">
|
||||
|
|
@ -262,11 +252,6 @@ import { IconPlant } from "@tabler/icons-preact";
|
|||
|
||||
const modeStationBtn = document.getElementById("overview-mode-station");
|
||||
const modeApstaBtn = document.getElementById("overview-mode-apsta");
|
||||
const apstaForm = document.getElementById("apsta-form");
|
||||
const ovApSsid = document.getElementById("ov-ap-ssid") as HTMLInputElement | null;
|
||||
const ovApPassword = document.getElementById("ov-ap-password") as HTMLInputElement | null;
|
||||
const ovApCancel = document.getElementById("ov-ap-cancel");
|
||||
const ovApApply = document.getElementById("ov-ap-apply") as HTMLButtonElement | null;
|
||||
|
||||
const forgetBtn = document.getElementById("overview-forget-btn");
|
||||
const errorModal = document.getElementById("overview-network-error-modal") as HTMLDialogElement | null;
|
||||
|
|
@ -483,42 +468,16 @@ import { IconPlant } from "@tabler/icons-preact";
|
|||
});
|
||||
|
||||
// ---------- Mode switch ----------
|
||||
// Both buttons just open their respective modals. The modal's own Save handler
|
||||
// builds the NetworkConfigNVS and calls send_new_network_configuration_to_alpha.
|
||||
modeStationBtn?.addEventListener("click", () => {
|
||||
// "Switch to Station" = re-run the wizard. Easiest path is to nuke SSID_Station
|
||||
// locally so index.astro shows the wizard. We don't push to the device yet —
|
||||
// the wizard's Apply step does that.
|
||||
const baseCfg = $current_network_configuration.get();
|
||||
$current_network_configuration.set({ ...baseCfg, SSID_Station: "" });
|
||||
const m = document.getElementById("station-config-modal") as HTMLDialogElement | null;
|
||||
m?.showModal();
|
||||
});
|
||||
|
||||
modeApstaBtn?.addEventListener("click", () => {
|
||||
// Open inline AP config form, prefilled with current AP values
|
||||
const cfg = $current_network_configuration.get();
|
||||
if (ovApSsid) ovApSsid.value = cfg.SSID_AP || "";
|
||||
if (ovApPassword) ovApPassword.value = cfg.Password_AP || "";
|
||||
apstaForm?.classList.remove("hidden");
|
||||
apstaForm?.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
||||
});
|
||||
|
||||
ovApCancel?.addEventListener("click", () => {
|
||||
apstaForm?.classList.add("hidden");
|
||||
});
|
||||
|
||||
ovApApply?.addEventListener("click", () => {
|
||||
const ssid = ovApSsid?.value.trim() ?? "";
|
||||
if (!ssid) {
|
||||
// Minimal inline feedback: focus the field
|
||||
ovApSsid?.focus();
|
||||
return;
|
||||
}
|
||||
const baseCfg = $current_network_configuration.get();
|
||||
send_new_network_configuration_to_alpha({
|
||||
...baseCfg,
|
||||
Connection_Mode: ConnectionMode.CONNECTION_MODE_APSTA,
|
||||
SSID_AP: ssid,
|
||||
Password_AP: ovApPassword?.value ?? "",
|
||||
});
|
||||
apstaForm?.classList.add("hidden");
|
||||
const m = document.getElementById("ap-config-modal") as HTMLDialogElement | null;
|
||||
m?.showModal();
|
||||
});
|
||||
|
||||
// ---------- Re-setup ----------
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
import IconEye from "../icons/IconEye.astro";
|
||||
import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
||||
// Icon refs use inline SVG (formerly imported IconEye / IconEyeClosed from a deleted folder).
|
||||
---
|
||||
|
||||
<dialog id="station-config-modal" class="modal modal-middle">
|
||||
|
|
@ -54,12 +53,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
<div class="relative">
|
||||
<input type="password" class="input w-full focus-within:bg-primary/10 focus-within:border-none focus-within:outline-primary pr-10" id="station-password" placeholder="WiFi password" />
|
||||
<button type="button" id="toggle-station-password-btn" class="absolute right-3 top-1/2 -translate-y-1/2 btn btn-ghost btn-xs p-1 min-h-0 h-7 hover:bg-primary hover:text-primary-content">
|
||||
<span id="station-eye-icon-open">
|
||||
<IconEye size={20} class="opacity-70 hover:opacity-100" />
|
||||
</span>
|
||||
<span id="station-eye-icon-closed" class="hidden">
|
||||
<IconEyeClosed size={20} class="opacity-70 hover:opacity-100" />
|
||||
</span>
|
||||
<span id="station-eye-text" class="text-xs opacity-70">show</span>
|
||||
</button>
|
||||
</div>
|
||||
<p id="station-password-error" class="mt-2 text-sm text-error hidden"></p>
|
||||
|
|
@ -156,19 +150,6 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
<li>
|
||||
The WiFi credentials must be valid to establish a working connection. Otherwise, the device will revert to the previous valid WiFi configuration, if there was one.
|
||||
</li>
|
||||
<li>The device remains reachable via Ethernet (if connected) or USB at any time.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="ethernet-warning" class="hidden alert alert-info py-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-5 w-5" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="font-semibold">Ethernet Detected</span>
|
||||
<ul class="list-disc list-inside text-sm space-y-0.5">
|
||||
<li>Ethernet and WiFi can be active simultaneously. The device will be reachable through both interfaces.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -200,10 +181,9 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
type WiFiNetwork,
|
||||
type NetworkConfigNVS,
|
||||
ConnectionMode,
|
||||
AntennaSelection,
|
||||
$current_network_configuration,
|
||||
send_new_network_configuration_to_alpha,
|
||||
} from "../backend_components/NetworkManagerStore";
|
||||
} from "./NetworkManagerStore";
|
||||
|
||||
import {
|
||||
is_valid_ip_format,
|
||||
|
|
@ -211,7 +191,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
isPracticalNetmask,
|
||||
isInValidHostRange,
|
||||
isInSameSubnet,
|
||||
} from "../helper_scripts/IP_Subnetmask_validation";
|
||||
} from "./helper_scripts/IP_Subnetmask_validation";
|
||||
|
||||
const stationSSID = document.getElementById("station-ssid") as HTMLInputElement;
|
||||
const stationSsidError = document.getElementById("station-ssid-error");
|
||||
|
|
@ -222,15 +202,13 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
const scanList = document.getElementById("network-scan-list");
|
||||
const refreshBtnRow = document.getElementById("refresh-btn-row");
|
||||
const toggleStationPasswordBtn = document.getElementById("toggle-station-password-btn") as HTMLButtonElement | null;
|
||||
const stationEyeOpen = document.getElementById("station-eye-icon-open");
|
||||
const stationEyeClosed = document.getElementById("station-eye-icon-closed");
|
||||
const stationEyeText = document.getElementById("station-eye-text");
|
||||
|
||||
toggleStationPasswordBtn?.addEventListener("click", () => {
|
||||
if (!stationPassword) return;
|
||||
const isVisible = stationPassword.type === "text";
|
||||
stationPassword.type = isVisible ? "password" : "text";
|
||||
stationEyeOpen?.classList.toggle("hidden", !isVisible);
|
||||
stationEyeClosed?.classList.toggle("hidden", isVisible);
|
||||
if (stationEyeText) stationEyeText.textContent = isVisible ? "show" : "hide";
|
||||
});
|
||||
|
||||
const staticIpToggle = document.getElementById("static-ip-toggle-modal") as HTMLInputElement;
|
||||
|
|
@ -542,8 +520,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
scanList?.classList.remove("hidden");
|
||||
selectedNetworkForConfirm = null;
|
||||
if (stationPassword) stationPassword.type = "password";
|
||||
stationEyeOpen?.classList.remove("hidden");
|
||||
stationEyeClosed?.classList.add("hidden");
|
||||
if (stationEyeText) stationEyeText.textContent = "show";
|
||||
performScan();
|
||||
}
|
||||
});
|
||||
|
|
@ -594,8 +571,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
scanList?.classList.remove("hidden");
|
||||
selectedNetworkForConfirm = null;
|
||||
if (stationPassword) stationPassword.type = "password";
|
||||
stationEyeOpen?.classList.remove("hidden");
|
||||
stationEyeClosed?.classList.add("hidden");
|
||||
if (stationEyeText) stationEyeText.textContent = "show";
|
||||
clear_scanned_wifi_networks();
|
||||
renderNetworkList([]);
|
||||
});
|
||||
|
|
@ -713,32 +689,20 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
let pendingConfig: NetworkConfigNVS | null = null;
|
||||
|
||||
saveStationBtn?.addEventListener("click", () => {
|
||||
const _currCfg = $current_network_configuration.get();
|
||||
const _newStaDHCP = !staticIpToggle?.checked; // toggle checked = static IP, unchecked = DHCP
|
||||
const _staMode = _currCfg.DHCP_Mode_Ethernet
|
||||
? (_newStaDHCP ? ConnectionMode.CONNECTION_MODE_ETH_DHCP_STA_DHCP : ConnectionMode.CONNECTION_MODE_ETH_DHCP_STA_STATIC)
|
||||
: (_newStaDHCP ? ConnectionMode.CONNECTION_MODE_ETH_STATIC_STA_DHCP : ConnectionMode.CONNECTION_MODE_ETH_STATIC_STA_STATIC);
|
||||
const _cfg = $current_network_configuration.get();
|
||||
const _newStaDHCP = !staticIpToggle?.checked; // toggle checked = static IP, unchecked = DHCP
|
||||
// No ethernet variants anymore — STA is either DHCP or STATIC, period.
|
||||
const _staMode = _newStaDHCP ? ConnectionMode.CONNECTION_MODE_STA_DHCP : ConnectionMode.CONNECTION_MODE_STA_STATIC;
|
||||
let temp_station_network_config: NetworkConfigNVS = {
|
||||
Connection_Mode: _staMode,
|
||||
Antenna_Power: _cfg.Antenna_Power,
|
||||
Antenna_Selection: _cfg.Antenna_Selection,
|
||||
DHCP_Mode_Station: _cfg.DHCP_Mode_Station,
|
||||
DHCP_Mode_Ethernet: _cfg.DHCP_Mode_Ethernet,
|
||||
DHCP_Mode_Station: _newStaDHCP,
|
||||
AP_Channel: _cfg.AP_Channel,
|
||||
WiFi_Enabled: _cfg.WiFi_Enabled,
|
||||
IP_Address_Ethernet: _cfg.IP_Address_Ethernet,
|
||||
IP_Address_Station: _cfg.IP_Address_Station,
|
||||
Gateway_IP_Address_Ethernet: _cfg.Gateway_IP_Address_Ethernet,
|
||||
Gateway_IP_Address_Station: _cfg.Gateway_IP_Address_Station,
|
||||
Netmask_Ethernet: _cfg.Netmask_Ethernet,
|
||||
Netmask_Station: _cfg.Netmask_Station,
|
||||
Static_Cfg_IP_Address_Ethernet: _cfg.Static_Cfg_IP_Address_Ethernet,
|
||||
Static_Cfg_IP_Address_Station: _cfg.Static_Cfg_IP_Address_Station,
|
||||
Static_Cfg_IP_Address_Station: "",
|
||||
Static_Cfg_Gateway_IP_Address_Station: "",
|
||||
Static_Cfg_Gateway_IP_Address_Ethernet: _cfg.Static_Cfg_Gateway_IP_Address_Ethernet,
|
||||
Static_Cfg_Netmask_Station: "",
|
||||
Static_Cfg_Netmask_Ethernet: _cfg.Static_Cfg_Netmask_Ethernet,
|
||||
SSID_Station: "",
|
||||
Password_Station: "",
|
||||
SSID_AP: _cfg.SSID_AP,
|
||||
|
|
@ -903,7 +867,7 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
temp_station_network_config.SSID_Station = stationSSID.value;
|
||||
temp_station_network_config.Password_Station = stationPassword.value;
|
||||
temp_station_network_config.DHCP_Mode_Station = false;
|
||||
temp_station_network_config.WiFi_Enabled = true;
|
||||
// WiFi is always on for this board — no WiFi_Enabled field needed.
|
||||
}
|
||||
} else {
|
||||
// enable DHCP mode
|
||||
|
|
@ -913,7 +877,6 @@ import IconEyeClosed from "../icons/IconEyeClosed.astro";
|
|||
temp_station_network_config.SSID_Station = stationSSID.value;
|
||||
temp_station_network_config.Password_Station = stationPassword.value;
|
||||
temp_station_network_config.DHCP_Mode_Station = true;
|
||||
temp_station_network_config.WiFi_Enabled = true;
|
||||
}
|
||||
|
||||
// Store the config and show confirmation view
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue