Skip to content

Commit

Permalink
Improve Wifi configuration UI (#22471)
Browse files Browse the repository at this point in the history
* Improve Wifi configuration UI

* some UI tweaks based on comments

* change label and remove DNS on reset

* remove mock code
  • Loading branch information
MindFreeze authored Oct 24, 2024
1 parent 5843877 commit fc9a095
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 49 deletions.
4 changes: 2 additions & 2 deletions src/data/hassio/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface NetworkInterface {
ipv4?: Partial<IpConfiguration>;
ipv6?: Partial<IpConfiguration>;
type: "ethernet" | "wireless" | "vlan";
wifi?: Partial<WifiConfiguration>;
wifi?: Partial<WifiConfiguration> | null;
}

interface DockerNetwork {
Expand All @@ -27,7 +27,7 @@ interface DockerNetwork {
interface: string;
}

interface AccessPoint {
export interface AccessPoint {
mode: "infrastructure" | "mesh" | "adhoc" | "ap";
ssid: string;
mac: string;
Expand Down
139 changes: 93 additions & 46 deletions src/panels/config/network/supervisor-network.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { mdiDeleteOutline, mdiPlus, mdiMenuDown } from "@mdi/js";
import { mdiDeleteOutline, mdiPlus, mdiMenuDown, mdiWifi } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { cache } from "lit/directives/cache";
Expand All @@ -20,7 +20,7 @@ import "../../../components/ha-textfield";
import type { HaTextField } from "../../../components/ha-textfield";
import { extractApiErrorMessage } from "../../../data/hassio/common";
import {
AccessPoints,
AccessPoint,
accesspointScan,
fetchNetworkInfo,
formatAddress,
Expand Down Expand Up @@ -58,7 +58,7 @@ const PREDEFINED_DNS = {
export class HassioNetwork extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;

@state() private _accessPoints?: AccessPoints;
@state() private _accessPoints: AccessPoint[] = [];

@state() private _curTabIndex = 0;

Expand Down Expand Up @@ -113,33 +113,32 @@ export class HassioNetwork extends LitElement {
</mwc-tab>`
)}
</mwc-tab-bar>`
: ""}
: nothing}
${cache(this._renderTab())}
</ha-card>
`;
}

private _renderTab() {
return html`<div class="card-content">
${IP_VERSIONS.map((version) =>
this._interface![version] ? this._renderIPConfiguration(version) : ""
)}
${this._interface?.type === "wireless"
? html`
<ha-expansion-panel
.header=${this.hass.localize(
"ui.panel.config.network.supervisor.wifi"
)}
outlined
.expanded=${!this._interface?.wifi?.ssid}
>
${this._interface?.wifi?.ssid
? html`<p>
<ha-svg-icon slot="icon" .path=${mdiWifi}></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.network.supervisor.connected_to",
{ ssid: this._interface?.wifi?.ssid }
)}
</p>`
: ""}
: nothing}
<ha-button
class="scan"
@click=${this._scanForAP}
Expand All @@ -151,37 +150,34 @@ export class HassioNetwork extends LitElement {
: this.hass.localize(
"ui.panel.config.network.supervisor.scan_ap"
)}
<ha-svg-icon slot="icon" .path=${mdiWifi}></ha-svg-icon>
</ha-button>
${this._accessPoints &&
this._accessPoints.accesspoints &&
this._accessPoints.accesspoints.length !== 0
${this._accessPoints.length
? html`
<mwc-list>
${this._accessPoints.accesspoints
.filter((ap) => ap.ssid)
.map(
(ap) => html`
<ha-list-item
twoline
@click=${this._selectAP}
.activated=${ap.ssid ===
this._wifiConfiguration?.ssid}
.ap=${ap}
>
<span>${ap.ssid}</span>
<span slot="secondary">
${ap.mac} -
${this.hass.localize(
"ui.panel.config.network.supervisor.signal_strength"
)}:
${ap.signal}
</span>
</ha-list-item>
`
)}
${this._accessPoints.map(
(ap) => html`
<ha-list-item
twoline
@click=${this._selectAP}
.activated=${ap.ssid ===
this._wifiConfiguration?.ssid}
.ap=${ap}
>
<span>${ap.ssid}</span>
<span slot="secondary">
${ap.mac} -
${this.hass.localize(
"ui.panel.config.network.supervisor.signal_strength"
)}:
${ap.signal}
</span>
</ha-list-item>
`
)}
</mwc-list>
`
: ""}
: nothing}
${this._wifiConfiguration
? html`
<div class="radio-row">
Expand Down Expand Up @@ -244,19 +240,24 @@ export class HassioNetwork extends LitElement {
>
</ha-password-field>
`
: ""}
: nothing}
`
: ""}
: nothing}
</ha-expansion-panel>
`
: ""}
: nothing}
${IP_VERSIONS.map((version) =>
this._interface![version]
? this._renderIPConfiguration(version)
: nothing
)}
${this._dirty
? html`<ha-alert alert-type="warning">
${this.hass.localize(
"ui.panel.config.network.supervisor.warning"
)}
</ha-alert>`
: ""}
: nothing}
</div>
<div class="card-actions">
<ha-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
Expand All @@ -265,11 +266,19 @@ export class HassioNetwork extends LitElement {
</ha-circular-progress>`
: this.hass.localize("ui.common.save")}
</ha-button>
<ha-button @click=${this._clear}>
${this.hass.localize("ui.panel.config.network.supervisor.reset")}
</ha-button>
</div>`;
}

private _selectAP(event) {
this._wifiConfiguration = event.currentTarget.ap;
IP_VERSIONS.forEach((version) => {
if (this._interface![version]!.method === "disabled") {
this._interface![version]!.method = "auto";
}
});
this._dirty = true;
}

Expand All @@ -279,10 +288,22 @@ export class HassioNetwork extends LitElement {
}
this._scanning = true;
try {
this._accessPoints = await accesspointScan(
this.hass,
this._interface.interface
);
const aps = await accesspointScan(this.hass, this._interface.interface);
this._accessPoints = [];
aps.accesspoints?.forEach((ap) => {
if (ap.ssid) {
// filter out duplicates
const existing = this._accessPoints.find((a) => a.ssid === ap.ssid);
if (!existing) {
this._accessPoints.push(ap);
} else if (ap.signal > existing.signal) {
this._accessPoints = this._accessPoints.filter(
(a) => a.ssid !== ap.ssid
);
this._accessPoints.push(ap);
}
}
});
} catch (err: any) {
showAlertDialog(this, {
title: "Failed to scan for accesspoints",
Expand All @@ -294,6 +315,13 @@ export class HassioNetwork extends LitElement {
}

private _renderIPConfiguration(version: string) {
const watingForSSID =
this._interface?.type === "wireless" &&
!this._wifiConfiguration?.ssid &&
!this._interface.wifi?.ssid;
if (watingForSSID) {
return nothing;
}
const nameservers = this._interface![version]?.nameservers || [];
if (nameservers.length === 0) {
nameservers.push(""); // always show input
Expand Down Expand Up @@ -484,7 +512,7 @@ export class HassioNetwork extends LitElement {
</ha-list-item>
</ha-button-menu>
`
: ""}
: nothing}
</ha-expansion-panel>
`;
}
Expand Down Expand Up @@ -529,9 +557,13 @@ export class HassioNetwork extends LitElement {
}

interfaceOptions.enabled =
this._wifiConfiguration !== undefined ||
interfaceOptions.ipv4?.method !== "disabled" ||
interfaceOptions.ipv6?.method !== "disabled";
// at least one ip version is enabled
(interfaceOptions.ipv4?.method !== "disabled" ||
interfaceOptions.ipv6?.method !== "disabled") &&
// require connection if this is a wireless interface
(this._interface!.type !== "wireless" ||
this._wifiConfiguration !== undefined ||
!!this._interface!.wifi);

try {
await updateNetworkInterface(
Expand All @@ -540,6 +572,7 @@ export class HassioNetwork extends LitElement {
interfaceOptions
);
this._dirty = false;
await this._fetchNetworkInfo();
} catch (err: any) {
showAlertDialog(this, {
title: this.hass.localize(
Expand All @@ -552,6 +585,20 @@ export class HassioNetwork extends LitElement {
}
}

private async _clear() {
await this._fetchNetworkInfo();
this._interface!.ipv4!.method = "auto";
this._interface!.ipv4!.nameservers = [];
this._interface!.ipv6!.method = "auto";
this._interface!.ipv6!.nameservers = [];
// removing the connection will disable the interface
// this is the only way to forget the wifi network right now
this._interface!.wifi = null;
this._wifiConfiguration = undefined;
this._dirty = true;
this.requestUpdate("_interface");
}

private async _handleTabActivated(ev: CustomEvent): Promise<void> {
if (this._dirty) {
const confirm = await showConfirmationDialog(this, {
Expand Down
3 changes: 2 additions & 1 deletion src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5225,7 +5225,8 @@
"supervisor": {
"title": "Configure network interfaces",
"connected_to": "Connected to {ssid}",
"scan_ap": "Scan for access points",
"scan_ap": "Search networks",
"reset": "Reset configuration",
"signal_strength": "Signal strength",
"open": "Open",
"wep": "WEP",
Expand Down

0 comments on commit fc9a095

Please sign in to comment.