mirror of
https://github.com/home-assistant/frontend.git
synced 2026-01-02 21:37:19 +00:00
Compare commits
6 Commits
renovate/l
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
209abf466d | ||
|
|
db9a3bd562 | ||
|
|
36ecaa6610 | ||
|
|
4f46d0f4a3 | ||
|
|
42ad47649d | ||
|
|
c62ee6e692 |
@@ -34,7 +34,7 @@
|
||||
"@codemirror/legacy-modes": "6.5.2",
|
||||
"@codemirror/search": "6.5.11",
|
||||
"@codemirror/state": "6.5.3",
|
||||
"@codemirror/view": "6.39.7",
|
||||
"@codemirror/view": "6.39.8",
|
||||
"@date-fns/tz": "1.4.1",
|
||||
"@egjs/hammerjs": "2.0.17",
|
||||
"@formatjs/intl-datetimeformat": "7.1.0",
|
||||
|
||||
@@ -163,7 +163,7 @@ class DialogImportBlueprint extends LitElement {
|
||||
</div>
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
slot="primaryAction"
|
||||
slot="secondaryAction"
|
||||
@click=${this.closeDialog}
|
||||
.disabled=${this._saving}
|
||||
>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { canShowPage } from "../../../common/config/can_show_page";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-navigation-list";
|
||||
import type { CloudStatus } from "../../../data/cloud";
|
||||
import { getConfigEntries } from "../../../data/config_entries";
|
||||
import type { PageNavigation } from "../../../layouts/hass-tabs-subpage";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@@ -17,13 +18,29 @@ class HaConfigNavigation extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public pages!: PageNavigation[];
|
||||
|
||||
@state() private _hasBluetoothConfigEntries = false;
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
getConfigEntries(this.hass, {
|
||||
domain: "bluetooth",
|
||||
}).then((bluetoothEntries) => {
|
||||
this._hasBluetoothConfigEntries = bluetoothEntries.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const pages = this.pages
|
||||
.filter((page) =>
|
||||
page.path === "#external-app-configuration"
|
||||
? this.hass.auth.external?.config.hasSettingsScreen
|
||||
: canShowPage(this.hass, page)
|
||||
)
|
||||
.filter((page) => {
|
||||
if (page.path === "#external-app-configuration") {
|
||||
return this.hass.auth.external?.config.hasSettingsScreen;
|
||||
}
|
||||
// Only show Bluetooth page if there are Bluetooth config entries
|
||||
if (page.component === "bluetooth") {
|
||||
return this._hasBluetoothConfigEntries;
|
||||
}
|
||||
return canShowPage(this.hass, page);
|
||||
})
|
||||
.map((page) => ({
|
||||
...page,
|
||||
name:
|
||||
|
||||
@@ -46,44 +46,54 @@ export class MatterConfigDashboard extends LitElement {
|
||||
href="/config/thread"
|
||||
slot="toolbar-icon"
|
||||
>
|
||||
Visit Thread Panel</ha-button
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.thread_panel"
|
||||
)}</ha-button
|
||||
>
|
||||
`
|
||||
: ""}
|
||||
<div class="content">
|
||||
<ha-card header="Matter">
|
||||
<ha-alert alert-type="warning"
|
||||
>Matter is still in the early phase of development, it is not
|
||||
meant to be used in production. This panel is for development
|
||||
only.</ha-alert
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.experimental_note"
|
||||
)}</ha-alert
|
||||
>
|
||||
<div class="card-content">
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
You can add Matter devices by commissing them if they are not
|
||||
setup yet, or share them from another controller and enter the
|
||||
share code.
|
||||
${this.hass.localize("ui.panel.config.matter.panel.add_devices")}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
${canCommissionMatterExternal(this.hass)
|
||||
? html`<ha-button
|
||||
appearance="plain"
|
||||
@click=${this._startMobileCommissioning}
|
||||
>Commission device with mobile app</ha-button
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.mobile_app_commisioning"
|
||||
)}</ha-button
|
||||
>`
|
||||
: ""}
|
||||
<ha-button appearance="plain" @click=${this._commission}
|
||||
>Commission device</ha-button
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.commission_device"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._acceptSharedDevice}
|
||||
>Add shared device</ha-button
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.add_shared_device"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._setWifi}
|
||||
>Set WiFi Credentials</ha-button
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.set_wifi_credentials"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._setThread}
|
||||
>Set Thread Credentials</ha-button
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.set_thread_credentials"
|
||||
)}</ha-button
|
||||
>
|
||||
</div>
|
||||
</ha-card>
|
||||
@@ -114,19 +124,31 @@ export class MatterConfigDashboard extends LitElement {
|
||||
private async _setWifi(): Promise<void> {
|
||||
this._error = undefined;
|
||||
const networkName = await showPromptDialog(this, {
|
||||
title: "Network name",
|
||||
inputLabel: "Network name",
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.network_name.title"
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.network_name.input_label"
|
||||
),
|
||||
inputType: "string",
|
||||
confirmText: "Continue",
|
||||
confirmText: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.network_name.confirm"
|
||||
),
|
||||
});
|
||||
if (!networkName) {
|
||||
return;
|
||||
}
|
||||
const psk = await showPromptDialog(this, {
|
||||
title: "Passcode",
|
||||
inputLabel: "Code",
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.passcode.title"
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.passcode.input_label"
|
||||
),
|
||||
inputType: "password",
|
||||
confirmText: "Set Wifi",
|
||||
confirmText: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.passcode.confirm"
|
||||
),
|
||||
});
|
||||
if (!psk) {
|
||||
return;
|
||||
@@ -140,10 +162,16 @@ export class MatterConfigDashboard extends LitElement {
|
||||
|
||||
private async _commission(): Promise<void> {
|
||||
const code = await showPromptDialog(this, {
|
||||
title: "Commission device",
|
||||
inputLabel: "Code",
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.commission_device.title"
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.commission_device.input_label"
|
||||
),
|
||||
inputType: "string",
|
||||
confirmText: "Commission",
|
||||
confirmText: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.commission_device.confirm"
|
||||
),
|
||||
});
|
||||
if (!code) {
|
||||
return;
|
||||
@@ -160,10 +188,16 @@ export class MatterConfigDashboard extends LitElement {
|
||||
|
||||
private async _acceptSharedDevice(): Promise<void> {
|
||||
const code = await showPromptDialog(this, {
|
||||
title: "Add shared device",
|
||||
inputLabel: "Pin",
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.add_shared_device.title"
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.add_shared_device.input_label"
|
||||
),
|
||||
inputType: "number",
|
||||
confirmText: "Accept device",
|
||||
confirmText: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.add_shared_device.confirm"
|
||||
),
|
||||
});
|
||||
if (!code) {
|
||||
return;
|
||||
@@ -180,10 +214,16 @@ export class MatterConfigDashboard extends LitElement {
|
||||
|
||||
private async _setThread(): Promise<void> {
|
||||
const code = await showPromptDialog(this, {
|
||||
title: "Set Thread operation",
|
||||
inputLabel: "Dataset",
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.set_thread.title"
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.set_thread.input_label"
|
||||
),
|
||||
inputType: "string",
|
||||
confirmText: "Set Thread",
|
||||
confirmText: this.hass.localize(
|
||||
"ui.panel.config.matter.panel.prompts.set_thread.confirm"
|
||||
),
|
||||
});
|
||||
if (!code) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-icon-next";
|
||||
import "../../../../../components/ha-list";
|
||||
import "../../../../../components/ha-list-item";
|
||||
import "../../../../../layouts/hass-loading-screen";
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import type { ConfigEntry } from "../../../../../data/config_entries";
|
||||
import { getConfigEntries } from "../../../../../data/config_entries";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import { caseInsensitiveStringCompare } from "../../../../../common/string/compare";
|
||||
|
||||
@customElement("zwave_js-config-entry-picker")
|
||||
class ZWaveJSConfigEntryPicker extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _configEntries?: ConfigEntry[];
|
||||
|
||||
protected async firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
await this._fetchConfigEntries();
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._configEntries) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
|
||||
if (this._configEntries.length === 0) {
|
||||
return html`
|
||||
<hass-subpage header="Z-Wave" .narrow=${this.narrow} .hass=${this.hass}>
|
||||
<div class="content">
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.picker.no_entries"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<hass-subpage header="Z-Wave" .narrow=${this.narrow} .hass=${this.hass}>
|
||||
<div class="content">
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.zwave_js.picker.title"
|
||||
)}
|
||||
>
|
||||
<ha-list>
|
||||
${this._configEntries.map(
|
||||
(entry) => html`
|
||||
<a
|
||||
href="/config/zwave_js/dashboard?config_entry=${entry.entry_id}"
|
||||
>
|
||||
<ha-list-item hasMeta>
|
||||
<span>${entry.title}</span>
|
||||
<ha-icon-next slot="meta"></ha-icon-next>
|
||||
</ha-list-item>
|
||||
</a>
|
||||
`
|
||||
)}
|
||||
</ha-list>
|
||||
</ha-card>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _fetchConfigEntries() {
|
||||
const entries = await getConfigEntries(this.hass, {
|
||||
domain: "zwave_js",
|
||||
});
|
||||
this._configEntries = entries.sort((a, b) =>
|
||||
caseInsensitiveStringCompare(a.title, b.title)
|
||||
);
|
||||
if (this._configEntries.length === 1) {
|
||||
navigate(
|
||||
`/config/zwave_js/dashboard?config_entry=${this._configEntries[0].entry_id}`,
|
||||
{ replace: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.content {
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
ha-card {
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
padding: 16px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
ha-list {
|
||||
--md-list-item-leading-space: var(--ha-space-4);
|
||||
--md-list-item-trailing-space: var(--ha-space-4);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zwave_js-config-entry-picker": ZWaveJSConfigEntryPicker;
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ import { customElement, property } from "lit/decorators";
|
||||
import type { RouterOptions } from "../../../../../layouts/hass-router-page";
|
||||
import { HassRouterPage } from "../../../../../layouts/hass-router-page";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage";
|
||||
import { getConfigEntries } from "../../../../../data/config_entries";
|
||||
|
||||
export const configTabs: PageNavigation[] = [
|
||||
{
|
||||
@@ -33,14 +31,36 @@ class ZWaveJSConfigRouter extends HassRouterPage {
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
private _configEntry = new URLSearchParams(window.location.search).get(
|
||||
"config_entry"
|
||||
);
|
||||
private _configEntry: string | null = null;
|
||||
|
||||
protected routerOptions: RouterOptions = {
|
||||
defaultPage: "dashboard",
|
||||
defaultPage: "picker",
|
||||
showLoading: true,
|
||||
// Make sure that we have a config entry in the URL before rendering other pages
|
||||
beforeRender: (page) => {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
if (searchParams.has("config_entry")) {
|
||||
this._configEntry = searchParams.get("config_entry");
|
||||
} else if (page === "picker") {
|
||||
this._configEntry = null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if ((!page || page === "picker") && this._configEntry) {
|
||||
return "dashboard";
|
||||
}
|
||||
|
||||
if ((!page || page !== "picker") && !this._configEntry) {
|
||||
return "picker";
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
routes: {
|
||||
picker: {
|
||||
tag: "zwave_js-config-entry-picker",
|
||||
load: () => import("./zwave_js-config-entry-picker"),
|
||||
},
|
||||
dashboard: {
|
||||
tag: "zwave_js-config-dashboard",
|
||||
load: () => import("./zwave_js-config-dashboard"),
|
||||
@@ -70,7 +90,6 @@ class ZWaveJSConfigRouter extends HassRouterPage {
|
||||
load: () => import("./zwave_js-network-visualization"),
|
||||
},
|
||||
},
|
||||
initialLoad: () => this._fetchConfigEntries(),
|
||||
};
|
||||
|
||||
protected updatePageEl(el): void {
|
||||
@@ -79,29 +98,6 @@ class ZWaveJSConfigRouter extends HassRouterPage {
|
||||
el.isWide = this.isWide;
|
||||
el.narrow = this.narrow;
|
||||
el.configEntryId = this._configEntry;
|
||||
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
if (this._configEntry && !searchParams.has("config_entry")) {
|
||||
searchParams.append("config_entry", this._configEntry);
|
||||
navigate(
|
||||
`${this.routeTail.prefix}${
|
||||
this.routeTail.path
|
||||
}?${searchParams.toString()}`,
|
||||
{ replace: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async _fetchConfigEntries() {
|
||||
if (this._configEntry) {
|
||||
return;
|
||||
}
|
||||
const entries = await getConfigEntries(this.hass, {
|
||||
domain: "zwave_js",
|
||||
});
|
||||
if (entries.length) {
|
||||
this._configEntry = entries[0].entry_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6827,9 +6827,50 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"picker": {
|
||||
"title": "Select Z-Wave network",
|
||||
"no_entries": "No Z-Wave networks configured. Set up the Z-Wave JS integration first."
|
||||
}
|
||||
},
|
||||
"matter": {
|
||||
"panel": {
|
||||
"thread_panel": "Visit Thread Panel",
|
||||
"experimental_note": "Matter is still in the early phase of development, it is not meant to be used in production. This panel is for development only.",
|
||||
"add_devices": "You can add Matter devices by commissioning them if they are not set up yet, or share them from another controller and enter the sharing code.",
|
||||
"mobile_app_commisioning": "Commission device with mobile app",
|
||||
"commission_device": "Commission device",
|
||||
"add_shared_device": "Add shared device",
|
||||
"set_wifi_credentials": "Set Wi-Fi Credentials",
|
||||
"set_thread_credentials": "Set Thread credentials",
|
||||
"prompts": {
|
||||
"network_name": {
|
||||
"title": "Network name",
|
||||
"input_label": "Network name",
|
||||
"confirm": "Continue"
|
||||
},
|
||||
"passcode": {
|
||||
"title": "Passcode",
|
||||
"input_label": "Code",
|
||||
"confirm": "Set Wifi"
|
||||
},
|
||||
"commission_device": {
|
||||
"title": "Commission device",
|
||||
"input_label": "Code",
|
||||
"confirm": "Commission"
|
||||
},
|
||||
"add_shared_device": {
|
||||
"title": "Add shared device",
|
||||
"input_label": "Pin",
|
||||
"confirm": "Accept device"
|
||||
},
|
||||
"set_thread": {
|
||||
"title": "Set Thread operation",
|
||||
"input_label": "Dataset",
|
||||
"confirm": "Set Thread"
|
||||
}
|
||||
}
|
||||
},
|
||||
"network_type": {
|
||||
"thread": "Thread",
|
||||
"wifi": "Wi-Fi",
|
||||
|
||||
16
yarn.lock
16
yarn.lock
@@ -1282,15 +1282,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@codemirror/view@npm:6.39.7, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
|
||||
version: 6.39.7
|
||||
resolution: "@codemirror/view@npm:6.39.7"
|
||||
"@codemirror/view@npm:6.39.8, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
|
||||
version: 6.39.8
|
||||
resolution: "@codemirror/view@npm:6.39.8"
|
||||
dependencies:
|
||||
"@codemirror/state": "npm:^6.5.0"
|
||||
crelt: "npm:^1.0.6"
|
||||
style-mod: "npm:^4.1.0"
|
||||
w3c-keyname: "npm:^2.2.4"
|
||||
checksum: 10/46057d484ece18e01a5d6423063a151b7ac646bf122f19cba8ddc4cdff6e99b1ac5d7fe923ffe829e3c34b669382251c0a130cdbcb8e681edebbe920e9ee11d5
|
||||
checksum: 10/a15941940fabc9b595da00a7760947cf7ce83f3f819be31250a73d2a1de5d1b5528a5803aa19c74656d2d7cbc39f47daec4962190ffc0849f4f359e45b4f1c3a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9010,7 +9010,7 @@ __metadata:
|
||||
"@codemirror/legacy-modes": "npm:6.5.2"
|
||||
"@codemirror/search": "npm:6.5.11"
|
||||
"@codemirror/state": "npm:6.5.3"
|
||||
"@codemirror/view": "npm:6.39.7"
|
||||
"@codemirror/view": "npm:6.39.8"
|
||||
"@date-fns/tz": "npm:1.4.1"
|
||||
"@egjs/hammerjs": "npm:2.0.17"
|
||||
"@formatjs/intl-datetimeformat": "npm:7.1.0"
|
||||
@@ -11996,11 +11996,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:~6.14.0":
|
||||
version: 6.14.0
|
||||
resolution: "qs@npm:6.14.0"
|
||||
version: 6.14.1
|
||||
resolution: "qs@npm:6.14.1"
|
||||
dependencies:
|
||||
side-channel: "npm:^1.1.0"
|
||||
checksum: 10/a60e49bbd51c935a8a4759e7505677b122e23bf392d6535b8fc31c1e447acba2c901235ecb192764013cd2781723dc1f61978b5fdd93cc31d7043d31cdc01974
|
||||
checksum: 10/34b5ab00a910df432d55180ef39c1d1375e550f098b5ec153b41787f1a6a6d7e5f9495593c3b112b77dbc6709d0ae18e55b82847a4c2bbbb0de1e8ccbb1794c5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user