mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Improve Wifi configuration UI (#22471)
* Improve Wifi configuration UI * some UI tweaks based on comments * change label and remove DNS on reset * remove mock code
This commit is contained in:
parent
5843877cc8
commit
fc9a0958d4
@ -17,7 +17,7 @@ export interface NetworkInterface {
|
|||||||
ipv4?: Partial<IpConfiguration>;
|
ipv4?: Partial<IpConfiguration>;
|
||||||
ipv6?: Partial<IpConfiguration>;
|
ipv6?: Partial<IpConfiguration>;
|
||||||
type: "ethernet" | "wireless" | "vlan";
|
type: "ethernet" | "wireless" | "vlan";
|
||||||
wifi?: Partial<WifiConfiguration>;
|
wifi?: Partial<WifiConfiguration> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DockerNetwork {
|
interface DockerNetwork {
|
||||||
@ -27,7 +27,7 @@ interface DockerNetwork {
|
|||||||
interface: string;
|
interface: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AccessPoint {
|
export interface AccessPoint {
|
||||||
mode: "infrastructure" | "mesh" | "adhoc" | "ap";
|
mode: "infrastructure" | "mesh" | "adhoc" | "ap";
|
||||||
ssid: string;
|
ssid: string;
|
||||||
mac: string;
|
mac: string;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "@material/mwc-tab";
|
import "@material/mwc-tab";
|
||||||
import "@material/mwc-tab-bar";
|
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 { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { cache } from "lit/directives/cache";
|
import { cache } from "lit/directives/cache";
|
||||||
@ -20,7 +20,7 @@ import "../../../components/ha-textfield";
|
|||||||
import type { HaTextField } from "../../../components/ha-textfield";
|
import type { HaTextField } from "../../../components/ha-textfield";
|
||||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||||
import {
|
import {
|
||||||
AccessPoints,
|
AccessPoint,
|
||||||
accesspointScan,
|
accesspointScan,
|
||||||
fetchNetworkInfo,
|
fetchNetworkInfo,
|
||||||
formatAddress,
|
formatAddress,
|
||||||
@ -58,7 +58,7 @@ const PREDEFINED_DNS = {
|
|||||||
export class HassioNetwork extends LitElement {
|
export class HassioNetwork extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() private _accessPoints?: AccessPoints;
|
@state() private _accessPoints: AccessPoint[] = [];
|
||||||
|
|
||||||
@state() private _curTabIndex = 0;
|
@state() private _curTabIndex = 0;
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ export class HassioNetwork extends LitElement {
|
|||||||
</mwc-tab>`
|
</mwc-tab>`
|
||||||
)}
|
)}
|
||||||
</mwc-tab-bar>`
|
</mwc-tab-bar>`
|
||||||
: ""}
|
: nothing}
|
||||||
${cache(this._renderTab())}
|
${cache(this._renderTab())}
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
@ -121,9 +121,6 @@ export class HassioNetwork extends LitElement {
|
|||||||
|
|
||||||
private _renderTab() {
|
private _renderTab() {
|
||||||
return html`<div class="card-content">
|
return html`<div class="card-content">
|
||||||
${IP_VERSIONS.map((version) =>
|
|
||||||
this._interface![version] ? this._renderIPConfiguration(version) : ""
|
|
||||||
)}
|
|
||||||
${this._interface?.type === "wireless"
|
${this._interface?.type === "wireless"
|
||||||
? html`
|
? html`
|
||||||
<ha-expansion-panel
|
<ha-expansion-panel
|
||||||
@ -131,15 +128,17 @@ export class HassioNetwork extends LitElement {
|
|||||||
"ui.panel.config.network.supervisor.wifi"
|
"ui.panel.config.network.supervisor.wifi"
|
||||||
)}
|
)}
|
||||||
outlined
|
outlined
|
||||||
|
.expanded=${!this._interface?.wifi?.ssid}
|
||||||
>
|
>
|
||||||
${this._interface?.wifi?.ssid
|
${this._interface?.wifi?.ssid
|
||||||
? html`<p>
|
? html`<p>
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiWifi}></ha-svg-icon>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.network.supervisor.connected_to",
|
"ui.panel.config.network.supervisor.connected_to",
|
||||||
{ ssid: this._interface?.wifi?.ssid }
|
{ ssid: this._interface?.wifi?.ssid }
|
||||||
)}
|
)}
|
||||||
</p>`
|
</p>`
|
||||||
: ""}
|
: nothing}
|
||||||
<ha-button
|
<ha-button
|
||||||
class="scan"
|
class="scan"
|
||||||
@click=${this._scanForAP}
|
@click=${this._scanForAP}
|
||||||
@ -151,37 +150,34 @@ export class HassioNetwork extends LitElement {
|
|||||||
: this.hass.localize(
|
: this.hass.localize(
|
||||||
"ui.panel.config.network.supervisor.scan_ap"
|
"ui.panel.config.network.supervisor.scan_ap"
|
||||||
)}
|
)}
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiWifi}></ha-svg-icon>
|
||||||
</ha-button>
|
</ha-button>
|
||||||
${this._accessPoints &&
|
${this._accessPoints.length
|
||||||
this._accessPoints.accesspoints &&
|
|
||||||
this._accessPoints.accesspoints.length !== 0
|
|
||||||
? html`
|
? html`
|
||||||
<mwc-list>
|
<mwc-list>
|
||||||
${this._accessPoints.accesspoints
|
${this._accessPoints.map(
|
||||||
.filter((ap) => ap.ssid)
|
(ap) => html`
|
||||||
.map(
|
<ha-list-item
|
||||||
(ap) => html`
|
twoline
|
||||||
<ha-list-item
|
@click=${this._selectAP}
|
||||||
twoline
|
.activated=${ap.ssid ===
|
||||||
@click=${this._selectAP}
|
this._wifiConfiguration?.ssid}
|
||||||
.activated=${ap.ssid ===
|
.ap=${ap}
|
||||||
this._wifiConfiguration?.ssid}
|
>
|
||||||
.ap=${ap}
|
<span>${ap.ssid}</span>
|
||||||
>
|
<span slot="secondary">
|
||||||
<span>${ap.ssid}</span>
|
${ap.mac} -
|
||||||
<span slot="secondary">
|
${this.hass.localize(
|
||||||
${ap.mac} -
|
"ui.panel.config.network.supervisor.signal_strength"
|
||||||
${this.hass.localize(
|
)}:
|
||||||
"ui.panel.config.network.supervisor.signal_strength"
|
${ap.signal}
|
||||||
)}:
|
</span>
|
||||||
${ap.signal}
|
</ha-list-item>
|
||||||
</span>
|
`
|
||||||
</ha-list-item>
|
)}
|
||||||
`
|
|
||||||
)}
|
|
||||||
</mwc-list>
|
</mwc-list>
|
||||||
`
|
`
|
||||||
: ""}
|
: nothing}
|
||||||
${this._wifiConfiguration
|
${this._wifiConfiguration
|
||||||
? html`
|
? html`
|
||||||
<div class="radio-row">
|
<div class="radio-row">
|
||||||
@ -244,19 +240,24 @@ export class HassioNetwork extends LitElement {
|
|||||||
>
|
>
|
||||||
</ha-password-field>
|
</ha-password-field>
|
||||||
`
|
`
|
||||||
: ""}
|
: nothing}
|
||||||
`
|
`
|
||||||
: ""}
|
: nothing}
|
||||||
</ha-expansion-panel>
|
</ha-expansion-panel>
|
||||||
`
|
`
|
||||||
: ""}
|
: nothing}
|
||||||
|
${IP_VERSIONS.map((version) =>
|
||||||
|
this._interface![version]
|
||||||
|
? this._renderIPConfiguration(version)
|
||||||
|
: nothing
|
||||||
|
)}
|
||||||
${this._dirty
|
${this._dirty
|
||||||
? html`<ha-alert alert-type="warning">
|
? html`<ha-alert alert-type="warning">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.network.supervisor.warning"
|
"ui.panel.config.network.supervisor.warning"
|
||||||
)}
|
)}
|
||||||
</ha-alert>`
|
</ha-alert>`
|
||||||
: ""}
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
<ha-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
||||||
@ -265,11 +266,19 @@ export class HassioNetwork extends LitElement {
|
|||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.hass.localize("ui.common.save")}
|
: this.hass.localize("ui.common.save")}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
|
<ha-button @click=${this._clear}>
|
||||||
|
${this.hass.localize("ui.panel.config.network.supervisor.reset")}
|
||||||
|
</ha-button>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _selectAP(event) {
|
private _selectAP(event) {
|
||||||
this._wifiConfiguration = event.currentTarget.ap;
|
this._wifiConfiguration = event.currentTarget.ap;
|
||||||
|
IP_VERSIONS.forEach((version) => {
|
||||||
|
if (this._interface![version]!.method === "disabled") {
|
||||||
|
this._interface![version]!.method = "auto";
|
||||||
|
}
|
||||||
|
});
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,10 +288,22 @@ export class HassioNetwork extends LitElement {
|
|||||||
}
|
}
|
||||||
this._scanning = true;
|
this._scanning = true;
|
||||||
try {
|
try {
|
||||||
this._accessPoints = await accesspointScan(
|
const aps = await accesspointScan(this.hass, this._interface.interface);
|
||||||
this.hass,
|
this._accessPoints = [];
|
||||||
this._interface.interface
|
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) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to scan for accesspoints",
|
title: "Failed to scan for accesspoints",
|
||||||
@ -294,6 +315,13 @@ export class HassioNetwork extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _renderIPConfiguration(version: string) {
|
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 || [];
|
const nameservers = this._interface![version]?.nameservers || [];
|
||||||
if (nameservers.length === 0) {
|
if (nameservers.length === 0) {
|
||||||
nameservers.push(""); // always show input
|
nameservers.push(""); // always show input
|
||||||
@ -484,7 +512,7 @@ export class HassioNetwork extends LitElement {
|
|||||||
</ha-list-item>
|
</ha-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
`
|
`
|
||||||
: ""}
|
: nothing}
|
||||||
</ha-expansion-panel>
|
</ha-expansion-panel>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -529,9 +557,13 @@ export class HassioNetwork extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interfaceOptions.enabled =
|
interfaceOptions.enabled =
|
||||||
this._wifiConfiguration !== undefined ||
|
// at least one ip version is enabled
|
||||||
interfaceOptions.ipv4?.method !== "disabled" ||
|
(interfaceOptions.ipv4?.method !== "disabled" ||
|
||||||
interfaceOptions.ipv6?.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 {
|
try {
|
||||||
await updateNetworkInterface(
|
await updateNetworkInterface(
|
||||||
@ -540,6 +572,7 @@ export class HassioNetwork extends LitElement {
|
|||||||
interfaceOptions
|
interfaceOptions
|
||||||
);
|
);
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
|
await this._fetchNetworkInfo();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
@ -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> {
|
private async _handleTabActivated(ev: CustomEvent): Promise<void> {
|
||||||
if (this._dirty) {
|
if (this._dirty) {
|
||||||
const confirm = await showConfirmationDialog(this, {
|
const confirm = await showConfirmationDialog(this, {
|
||||||
|
@ -5225,7 +5225,8 @@
|
|||||||
"supervisor": {
|
"supervisor": {
|
||||||
"title": "Configure network interfaces",
|
"title": "Configure network interfaces",
|
||||||
"connected_to": "Connected to {ssid}",
|
"connected_to": "Connected to {ssid}",
|
||||||
"scan_ap": "Scan for access points",
|
"scan_ap": "Search networks",
|
||||||
|
"reset": "Reset configuration",
|
||||||
"signal_strength": "Signal strength",
|
"signal_strength": "Signal strength",
|
||||||
"open": "Open",
|
"open": "Open",
|
||||||
"wep": "WEP",
|
"wep": "WEP",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user