diff --git a/pyproject.toml b/pyproject.toml
index 9527c33656..058f7ffd6f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
-version = "20240205.0"
+version = "20240207.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"
diff --git a/src/components/entity/ha-state-label-badge.ts b/src/components/entity/ha-state-label-badge.ts
index 48854167a5..91a90673e8 100644
--- a/src/components/entity/ha-state-label-badge.ts
+++ b/src/components/entity/ha-state-label-badge.ts
@@ -133,9 +133,9 @@ export class HaStateLabelBadge extends LitElement {
entityState,
this._timerTimeRemaining
)}
- .description=${this.showName === false
- ? undefined
- : this.name ?? computeStateName(entityState)}
+ .description=${this.showName
+ ? this.name ?? computeStateName(entityState)
+ : undefined}
>
${!image && showIcon
? html`
-
- ${this.hass.localize(
- "ui.panel.config.cloud.login.forgot_password"
- )}
-
+
+ ${this.hass.localize(
+ "ui.panel.config.cloud.login.forgot_password"
+ )}
+
@@ -311,11 +311,6 @@ export class CloudLogin extends LitElement {
display: flex;
flex-direction: column;
}
- .pwd-forgot-link {
- color: var(--secondary-text-color) !important;
- text-align: right !important;
- align-self: flex-end;
- }
`,
];
}
diff --git a/src/panels/config/integrations/integration-panels/matter/dialog-matter-open-commissioning-window.ts b/src/panels/config/integrations/integration-panels/matter/dialog-matter-open-commissioning-window.ts
index 6125b1ef97..ec3d5ff3a0 100644
--- a/src/panels/config/integrations/integration-panels/matter/dialog-matter-open-commissioning-window.ts
+++ b/src/panels/config/integrations/integration-panels/matter/dialog-matter-open-commissioning-window.ts
@@ -1,18 +1,21 @@
import "@material/mwc-button/mwc-button";
-import { mdiCheckCircle, mdiCloseCircle } from "@mdi/js";
-import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { mdiCloseCircle } from "@mdi/js";
+import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../../../../../components/ha-circular-progress";
-import "../../../../../components/ha-qr-code";
import { createCloseHeading } from "../../../../../components/ha-dialog";
+import "../../../../../components/ha-qr-code";
+import { domainToName } from "../../../../../data/integration";
import {
- openMatterCommissioningWindow,
MatterCommissioningParameters,
+ openMatterCommissioningWindow,
} from "../../../../../data/matter";
import { haStyleDialog } from "../../../../../resources/styles";
import { HomeAssistant } from "../../../../../types";
+import { brandsUrl } from "../../../../../util/brands-url";
import { MatterOpenCommissioningWindowDialogParams } from "./show-dialog-matter-open-commissioning-window";
+import { copyToClipboard } from "../../../../../common/util/copy-clipboard";
@customElement("dialog-matter-open-commissioning-window")
class DialogMatterOpenCommissioningWindow extends LitElement {
@@ -52,28 +55,46 @@ class DialogMatterOpenCommissioningWindow extends LitElement {
${this.hass.localize(
"ui.panel.config.matter.open_commissioning_window.success"
)}
+
+ ${this.hass.localize(
+ "ui.panel.config.matter.open_commissioning_window.scan_code"
+ )}
-
-
-
-
- ${this.hass.localize(
- "ui.panel.config.matter.open_commissioning_window.sharing_code"
- )}: ${this._commissionParams.setup_manual_code}
-
+
+
+
+
+
${this._commissionParams.setup_manual_code.substring(
+ 0,
+ 4
+ )}-${this._commissionParams.setup_manual_code.substring(
+ 4,
+ 7
+ )}-${this._commissionParams.setup_manual_code.substring(
+ 7
+ )}
-
-
-
- ${this.hass.localize("ui.common.close")}
+
+ ${this.hass.localize(
+ "ui.panel.config.matter.open_commissioning_window.copy_code"
+ )}
`
: this._status === "started"
@@ -145,9 +166,18 @@ class DialogMatterOpenCommissioningWindow extends LitElement {
}
}
+ private async _copyCode() {
+ if (!this._commissionParams) {
+ return;
+ }
+ await copyToClipboard(this._commissionParams.setup_manual_code);
+ this.closeDialog();
+ }
+
public closeDialog(): void {
this.device_id = undefined;
this._status = undefined;
+ this._commissionParams = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
@@ -193,6 +223,30 @@ class DialogMatterOpenCommissioningWindow extends LitElement {
.flex-container ha-svg-icon {
margin-right: 20px;
}
+
+ .sharing-code-container {
+ display: flex;
+ justify-content: center;
+ padding-top: 16px;
+ }
+
+ .sharing-code {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ border: 2px solid;
+ border-radius: 16px;
+ padding: 16px;
+ }
+
+ .sharing-code img {
+ width: 160px;
+ margin-bottom: 8px;
+ }
+
+ .code {
+ font-family: monospace;
+ }
`,
];
}
diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts
index e6f601199c..dae3bae725 100644
--- a/src/panels/history/ha-panel-history.ts
+++ b/src/panels/history/ha-panel-history.ts
@@ -55,6 +55,7 @@ import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types";
import { fileDownload } from "../../util/file_download";
import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
+import { computeDomain } from "../../common/entity/compute_domain";
class HaPanelHistory extends SubscribeMixin(LitElement) {
@property({ attribute: false }) hass!: HomeAssistant;
@@ -657,7 +658,8 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
}
private _downloadHistory() {
- const entities = this._getEntityIds();
+ // Make a copy because getEntityIDs is memoized and sort works in-place
+ const entities = [...this._getEntityIds()].sort();
if (entities.length === 0 || !this._mungedStateHistory) {
showAlertDialog(this, {
title: this.hass.localize("ui.panel.history.download_data_error"),
@@ -667,12 +669,46 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
return;
}
- const csv: string[] = ["entity_id,state,last_changed\n"];
+ const csv: string[] = [""]; // headers will be replaced later.
+ const headers = ["entity_id", "state", "last_changed"];
+ const processedDomainAttributes = new Set();
+ const domainAttributes: Record> = {
+ climate: {
+ current_temperature: 0,
+ hvac_action: 0,
+ target_temp_high: 0,
+ target_temp_low: 0,
+ temperature: 0,
+ },
+ humidifier: {
+ action: 0,
+ current_humidity: 0,
+ humidity: 0,
+ },
+ water_heater: {
+ current_temperature: 0,
+ operation_mode: 0,
+ temperature: 0,
+ },
+ };
const formatDate = (number) => new Date(number).toISOString();
for (const line of this._mungedStateHistory.line) {
for (const entity of line.data) {
const entityId = entity.entity_id;
+ const domain = computeDomain(entityId);
+ const extraAttributes = domainAttributes[domain];
+
+ // Add extra attributes to headers if needed
+ if (extraAttributes && !processedDomainAttributes.has(domain)) {
+ processedDomainAttributes.add(domain);
+ let index = headers.length;
+ for (const attr of Object.keys(extraAttributes)) {
+ headers.push(attr);
+ extraAttributes[attr] = index;
+ index += 1;
+ }
+ }
if (entity.statistics) {
for (const s of entity.statistics) {
@@ -681,7 +717,19 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
}
for (const s of entity.states) {
- csv.push(`${entityId},${s.state},${formatDate(s.last_changed)}\n`);
+ const lastChanged = formatDate(s.last_changed);
+ const data = [entityId, s.state, lastChanged];
+
+ if (s.attributes && extraAttributes) {
+ const attrs = s.attributes;
+ for (const [attr, index] of Object.entries(extraAttributes)) {
+ if (attr in attrs) {
+ data[index] = attrs[attr];
+ }
+ }
+ }
+
+ csv.push(data.join(",") + "\n");
}
}
}
@@ -691,6 +739,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
csv.push(`${entityId},${s.state},${formatDate(s.last_changed)}\n`);
}
}
+ csv[0] = headers.join(",") + "\n";
const blob = new Blob(csv, {
type: "text/csv",
});
diff --git a/src/panels/lovelace/badges/hui-state-label-badge.ts b/src/panels/lovelace/badges/hui-state-label-badge.ts
index 92b06a1736..89751a720c 100644
--- a/src/panels/lovelace/badges/hui-state-label-badge.ts
+++ b/src/panels/lovelace/badges/hui-state-label-badge.ts
@@ -34,7 +34,7 @@ export class HuiStateLabelBadge extends LitElement implements LovelaceBadge {
.name=${this._config.name}
.icon=${this._config.icon}
.image=${this._config.image}
- .showName=${this._config.show_name}
+ .showName=${this._config.show_name ?? true}
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(this._config!.hold_action),
diff --git a/src/panels/lovelace/badges/types.ts b/src/panels/lovelace/badges/types.ts
index df5ba34dcd..c25c834539 100644
--- a/src/panels/lovelace/badges/types.ts
+++ b/src/panels/lovelace/badges/types.ts
@@ -17,6 +17,7 @@ export interface StateLabelBadgeConfig extends LovelaceBadgeConfig {
name?: string;
icon?: string;
image?: string;
+ show_name?: boolean;
tap_action?: ActionConfig;
hold_action?: ActionConfig;
double_tap_action?: ActionConfig;
diff --git a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts
index 57adc6f581..83a1c9ae08 100644
--- a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts
+++ b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts
@@ -29,26 +29,25 @@ export class HuiHorizontalStackCard extends HuiStackCard {
display: flex;
height: 100%;
}
- #root {
- --stack-card-side-margin: 4px;
- }
#root > * {
flex: 1 1 0;
margin: var(
--horizontal-stack-card-margin,
- var(--stack-card-margin, 0 var(--stack-card-side-margin))
+ var(--stack-card-margin, 0 4px)
);
min-width: 0;
}
- #root > *:first-child {
+ #root[dir="ltr"] > *:first-child {
margin-left: 0;
- margin-inline-start: 0;
- margin-inline-end: var(--stack-card-side-margin);
}
- #root > *:last-child {
+ #root[dir="ltr"] > *:last-child {
margin-right: 0;
- margin-inline-end: 0;
- margin-inline-start: var(--stack-card-side-margin);
+ }
+ #root[dir="rtl"] > *:first-child {
+ margin-right: 0;
+ }
+ #root[dir="rtl"] > *:last-child {
+ margin-left: 0;
}
`,
];
diff --git a/src/panels/lovelace/cards/hui-plant-status-card.ts b/src/panels/lovelace/cards/hui-plant-status-card.ts
index 80435b1f0b..c440952989 100644
--- a/src/panels/lovelace/cards/hui-plant-status-card.ts
+++ b/src/panels/lovelace/cards/hui-plant-status-card.ts
@@ -138,10 +138,14 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
tabindex="0"
.value=${item}
>
-
-
+
+ ${item === "battery"
+ ? html` `
+ : html` `}
extends LitElement
@@ -77,7 +78,9 @@ export abstract class HuiStackCard
${this._config.title
? html``
: ""}
- ${this._cards}
+
+ ${this._cards}
+
`;
}
diff --git a/src/panels/lovelace/elements/hui-state-badge-element.ts b/src/panels/lovelace/elements/hui-state-badge-element.ts
index e98c9210d8..446bae8cdc 100644
--- a/src/panels/lovelace/elements/hui-state-badge-element.ts
+++ b/src/panels/lovelace/elements/hui-state-badge-element.ts
@@ -58,6 +58,7 @@ export class HuiStateBadgeElement
: this._config.title === null
? ""
: this._config.title}
+ showName
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(this._config!.hold_action),
diff --git a/src/translations/en.json b/src/translations/en.json
index 0de04b08e3..cbeaab0b43 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -4662,8 +4662,9 @@
"start_commissioning": "Share device",
"in_progress": "We're communicating with the device. This may take some time.",
"failed": "The command failed. Additional information may be available in the logs.",
- "success": "Your device can now be added to another Matter controller, scan the QR code below or enter the sharing code in the app of the controller you want to add your device to.",
- "sharing_code": "Sharing code"
+ "success": "Your device is ready to be added to another Matter platform.",
+ "scan_code": "With their app, scan the QR code or enter the sharing code below to finish set up.",
+ "copy_code": "Copy code"
}
},
"tips": {