mirror of
https://github.com/home-assistant/frontend.git
synced 2026-02-15 07:25:54 +00:00
Add Matter status to config dashboard (#28825)
Co-authored-by: Norbert Rittel <norbert@rittel.de> Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
@@ -114,6 +114,15 @@ export const configSections: Record<string, PageNavigation[]> = {
|
||||
},
|
||||
],
|
||||
dashboard_2: [
|
||||
{
|
||||
path: "/config/matter",
|
||||
name: "Matter",
|
||||
iconPath:
|
||||
"M7.228375 6.41685c0.98855 0.80195 2.16365 1.3412 3.416275 1.56765V1.30093l1.3612 -0.7854275 1.360125 0.7854275V7.9845c1.252875 -0.226675 2.4283 -0.765875 3.41735 -1.56765l2.471225 1.4293c-4.019075 3.976275 -10.490025 3.976275 -14.5091 0l2.482925 -1.4293Zm3.00335 17.067575c1.43325 -5.47035 -1.8052 -11.074775 -7.2604 -12.564675v2.859675c1.189125 0.455 2.244125 1.202875 3.0672 2.174275L0.25 19.2955v1.5719l1.3611925 0.781175L7.39865 18.3068c0.430175 1.19825 0.550625 2.48575 0.35015 3.743l2.482925 1.434625ZM21.034 10.91975c-5.452225 1.4932 -8.6871 7.09635 -7.254025 12.564675l2.47655 -1.43035c-0.200025 -1.257275 -0.079575 -2.544675 0.35015 -3.743025l5.7832 3.337525L23.75 20.86315V19.2955L17.961475 15.9537c0.8233 -0.97115 1.878225 -1.718975 3.0672 -2.174275l0.005325 -2.859675Z",
|
||||
iconColor: "#2458B3",
|
||||
component: "matter",
|
||||
translationKey: "matter",
|
||||
},
|
||||
{
|
||||
path: "/config/zha",
|
||||
name: "Zigbee",
|
||||
|
||||
@@ -23,7 +23,6 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isDevVersion } from "../../../common/config/version";
|
||||
import { computeDeviceNameDisplay } from "../../../common/entity/compute_device_name";
|
||||
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
||||
import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
||||
@@ -213,10 +212,7 @@ class HaConfigEntryRow extends LitElement {
|
||||
? html`<ha-button slot="end" @click=${this._handleEnable}>
|
||||
${this.hass.localize("ui.common.enable")}
|
||||
</ha-button>`
|
||||
: configPanel &&
|
||||
(item.domain !== "matter" ||
|
||||
isDevVersion(this.hass.config.version)) &&
|
||||
!stateText
|
||||
: configPanel && !stateText
|
||||
? html`<a
|
||||
slot="end"
|
||||
href=${`/${configPanel}?config_entry=${item.entry_id}`}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { mdiAlertCircle, mdiCheckCircle, mdiPlus } from "@mdi/js";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../../../common/config/is_component_loaded";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-expansion-panel";
|
||||
import "../../../../../components/ha-fab";
|
||||
import "../../../../../components/ha-svg-icon";
|
||||
import type { ConfigEntry } from "../../../../../data/config_entries";
|
||||
import { getConfigEntries } from "../../../../../data/config_entries";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import {
|
||||
acceptSharedMatterDevice,
|
||||
canCommissionMatterExternal,
|
||||
@@ -18,7 +26,6 @@ import {
|
||||
import { showPromptDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
|
||||
@customElement("matter-config-dashboard")
|
||||
export class MatterConfigDashboard extends LitElement {
|
||||
@@ -26,6 +33,8 @@ export class MatterConfigDashboard extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _configEntry?: ConfigEntry;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
private _unsub?: UnsubscribeFunc;
|
||||
@@ -35,10 +44,33 @@ export class MatterConfigDashboard extends LitElement {
|
||||
this._stopRedirect();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected firstUpdated(changedProperties: PropertyValues) {
|
||||
super.firstUpdated(changedProperties);
|
||||
if (this.hass) {
|
||||
this._fetchConfigEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private _matterDeviceCount = memoizeOne(
|
||||
(devices: HomeAssistant["devices"]): number =>
|
||||
Object.values(devices).filter((device) =>
|
||||
device.identifiers.some((identifier) => identifier[0] === "matter")
|
||||
).length
|
||||
);
|
||||
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this._configEntry) {
|
||||
return nothing;
|
||||
}
|
||||
const isOnline = this._configEntry.state === "loaded";
|
||||
return html`
|
||||
<hass-subpage .narrow=${this.narrow} .hass=${this.hass} header="Matter">
|
||||
${isComponentLoaded(this.hass, "otbr")
|
||||
<hass-subpage
|
||||
.narrow=${this.narrow}
|
||||
.hass=${this.hass}
|
||||
header="Matter"
|
||||
has-fab
|
||||
>
|
||||
${isComponentLoaded(this.hass, "thread")
|
||||
? html`
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
@@ -51,53 +83,114 @@ export class MatterConfigDashboard extends LitElement {
|
||||
)}</ha-button
|
||||
>
|
||||
`
|
||||
: ""}
|
||||
<div class="content">
|
||||
<ha-card header="Matter">
|
||||
<ha-alert alert-type="warning"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.experimental_note"
|
||||
)}</ha-alert
|
||||
>
|
||||
: nothing}
|
||||
<div class="container">
|
||||
<ha-card class="network-status">
|
||||
<div class="card-content">
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
${this.hass.localize("ui.panel.config.matter.panel.add_devices")}
|
||||
<div class="heading">
|
||||
<div class="icon">
|
||||
<ha-svg-icon
|
||||
.path=${isOnline ? mdiCheckCircle : mdiAlertCircle}
|
||||
class=${isOnline ? "online" : "offline"}
|
||||
></ha-svg-icon>
|
||||
</div>
|
||||
<div class="details">
|
||||
Matter
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.status_title"
|
||||
)}:
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.matter.panel.status_${isOnline ? "online" : "offline"}`
|
||||
)}<br />
|
||||
<small>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.devices",
|
||||
{ count: this._matterDeviceCount(this.hass.devices) }
|
||||
)}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
${canCommissionMatterExternal(this.hass)
|
||||
? html`<ha-button
|
||||
appearance="plain"
|
||||
@click=${this._startMobileCommissioning}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.mobile_app_commisioning"
|
||||
)}</ha-button
|
||||
>`
|
||||
: ""}
|
||||
<ha-button appearance="plain" @click=${this._commission}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.commission_device"
|
||||
)}</ha-button
|
||||
<ha-button
|
||||
href=${`/config/devices/dashboard?historyBack=1&config_entry=${this._configEntry?.entry_id}`}
|
||||
appearance="plain"
|
||||
size="small"
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._acceptSharedDevice}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.add_shared_device"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._setWifi}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.set_wifi_credentials"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._setThread}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.set_thread_credentials"
|
||||
)}</ha-button
|
||||
${this.hass.localize("ui.panel.config.devices.caption")}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
appearance="plain"
|
||||
size="small"
|
||||
href=${`/config/entities/dashboard?historyBack=1&config_entry=${this._configEntry?.entry_id}`}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.entities.caption")}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
<ha-expansion-panel
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.developer_tools_title"
|
||||
)}
|
||||
.secondary=${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.developer_tools_description"
|
||||
)}
|
||||
>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: nothing}
|
||||
<div class="dev-tools-content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.developer_tools_info"
|
||||
)}
|
||||
</p>
|
||||
<div class="dev-tools-actions">
|
||||
${canCommissionMatterExternal(this.hass)
|
||||
? html`<ha-button
|
||||
appearance="plain"
|
||||
@click=${this._startMobileCommissioning}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.mobile_app_commisioning"
|
||||
)}</ha-button
|
||||
>`
|
||||
: nothing}
|
||||
<ha-button appearance="plain" @click=${this._commission}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.commission_device"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._acceptSharedDevice}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.add_shared_device"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._setWifi}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.set_wifi_credentials"
|
||||
)}</ha-button
|
||||
>
|
||||
<ha-button appearance="plain" @click=${this._setThread}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.set_thread_credentials"
|
||||
)}</ha-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</ha-expansion-panel>
|
||||
</div>
|
||||
|
||||
<a href="/config/matter/add" slot="fab">
|
||||
<ha-fab
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.matter.panel.add_device"
|
||||
)}
|
||||
extended
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||
</ha-fab>
|
||||
</a>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
@@ -236,27 +329,101 @@ export class MatterConfigDashboard extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
static styles = [
|
||||
haStyle,
|
||||
css`
|
||||
ha-alert[alert-type="warning"] {
|
||||
position: relative;
|
||||
top: -16px;
|
||||
}
|
||||
.content {
|
||||
padding: 24px 0 32px;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
direction: ltr;
|
||||
}
|
||||
ha-card:first-child {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
a[slot="toolbar-icon"] {
|
||||
text-decoration: none;
|
||||
}
|
||||
`,
|
||||
];
|
||||
private async _fetchConfigEntry(): Promise<void> {
|
||||
const configEntries = await getConfigEntries(this.hass, {
|
||||
domain: "matter",
|
||||
});
|
||||
if (configEntries.length) {
|
||||
this._configEntry = configEntries[0];
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
ha-card {
|
||||
margin: auto;
|
||||
margin-top: var(--ha-space-4);
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
ha-card .card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.network-status div.heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.network-status div.heading .icon {
|
||||
margin-inline-end: var(--ha-space-4);
|
||||
}
|
||||
|
||||
.network-status div.heading ha-svg-icon {
|
||||
--mdc-icon-size: 48px;
|
||||
}
|
||||
|
||||
.network-status div.heading .details {
|
||||
font-size: var(--ha-font-size-xl);
|
||||
}
|
||||
|
||||
.network-status small {
|
||||
font-size: var(--ha-font-size-m);
|
||||
}
|
||||
|
||||
.network-status .online {
|
||||
color: var(--state-on-color, var(--success-color));
|
||||
}
|
||||
|
||||
.network-status .offline {
|
||||
color: var(--error-color, var(--error-color));
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: var(--ha-space-2) var(--ha-space-4) var(--ha-space-4);
|
||||
}
|
||||
|
||||
ha-expansion-panel {
|
||||
margin: auto;
|
||||
margin-top: var(--ha-space-4);
|
||||
max-width: 500px;
|
||||
background: var(--card-background-color);
|
||||
border-radius: var(
|
||||
--ha-card-border-radius,
|
||||
var(--ha-border-radius-lg)
|
||||
);
|
||||
--expansion-panel-summary-padding: var(--ha-space-2) var(--ha-space-4);
|
||||
--expansion-panel-content-padding: 0 var(--ha-space-4);
|
||||
}
|
||||
|
||||
.dev-tools-content {
|
||||
padding: 0 0 var(--ha-space-4);
|
||||
}
|
||||
|
||||
.dev-tools-content p {
|
||||
margin: 0 0 var(--ha-space-4);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.dev-tools-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--ha-space-2);
|
||||
}
|
||||
|
||||
a[slot="toolbar-icon"] {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a[slot="fab"] {
|
||||
text-decoration: none;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -6845,9 +6845,15 @@
|
||||
},
|
||||
"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.",
|
||||
"thread_panel": "Visit Thread panel",
|
||||
"add_device": "Add device",
|
||||
"status_title": "status",
|
||||
"status_online": "online",
|
||||
"status_offline": "offline",
|
||||
"devices": "{count, plural,\n one {# device}\n other {# devices}\n}",
|
||||
"developer_tools_title": "Developer tools",
|
||||
"developer_tools_description": "Advanced commissioning options for development",
|
||||
"developer_tools_info": "These options are intended for developers and advanced users. In most cases, use the \"Add device\" button in the bottom right corner instead.",
|
||||
"mobile_app_commisioning": "Commission device with mobile app",
|
||||
"commission_device": "Commission device",
|
||||
"add_shared_device": "Add shared device",
|
||||
|
||||
Reference in New Issue
Block a user