Compare commits

..

50 Commits

Author SHA1 Message Date
Bram Kragten
365db51526 move default dashboard setting to user settings 2025-06-05 17:38:19 +01:00
Mathieu
8eb7fe8b0a Adjust tooltip positioning in ha-sidebar for not first lis… (#25696)
fix(tooltip): fix tooltip positioning in ha-sidebar for not first listbox
2025-06-05 04:35:32 +00:00
renovate[bot]
c8c2966d34 Update dependency gulp to v5.0.1 (#25698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 06:25:43 +02:00
renovate[bot]
a8768a5d9d Update dependency @bundle-stats/plugin-webpack-filter to v4.20.2 (#25692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 06:25:20 +02:00
karwosts
02bb7086e7 Hoist integration card tooltips (#25679) 2025-06-03 21:41:27 +02:00
renovate[bot]
42d8b2ae19 Update dependency lint-staged to v16 (#25463)
* Update dependency lint-staged to v16

* Remove shell parameter

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com>
2025-06-03 19:18:39 +00:00
renovate[bot]
e08f4a6bba Update dependency @types/chromecast-caf-receiver to v6.0.22 (#25681)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 17:32:25 +02:00
renovate[bot]
2e6c35d977 Update dependency hls.js to v1.6.4 (#25682)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 17:32:08 +02:00
renovate[bot]
17305a818b Update dependency eslint to v9.28.0 (#25683)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 01:32:02 +02:00
renovate[bot]
08389dad04 Update babel monorepo to v7.27.4 (#25680)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 22:36:58 +03:00
Bram Kragten
ab6ace46b5 Set answers to yes and no for cloud pipeline confirm (#25674) 2025-06-02 14:02:06 +00:00
renovate[bot]
535dedbbc4 Update dependency hls.js to v1.6.3 (#25669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 16:01:37 +02:00
renovate[bot]
412eb0c647 Update dependency @codemirror/view to v6.37.1 (#25672)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 16:01:29 +02:00
renovate[bot]
87c8ebd493 Update dependency @codemirror/view to v6.37.0 (#25664)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-01 09:31:21 +02:00
Simon Lamon
6e49f89126 Calendar add event button gap alignment (#25662)
Calendar gap alignment
2025-06-01 09:39:10 +03:00
ildar170975
a099e65a9d Fix "unavailable" state in Area card (#25063)
* fix "unavailable" state

* Show "-" for unavailable/undefined
2025-05-31 10:45:58 +03:00
renovate[bot]
11e4a9f056 Update dependency typescript-eslint to v8.33.0 (#25657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 17:52:29 +00:00
Bram Kragten
b617299eee Add css variables for start and end padding of tabs (#25654) 2025-05-30 16:48:15 +02:00
Bram Kragten
768f27b1b9 Add label to collapse button in data table groups (#25653) 2025-05-30 16:47:54 +02:00
Bram Kragten
5ed816df6d fix line height entity card (#25652) 2025-05-30 15:34:03 +02:00
renovate[bot]
6692ac7517 Update dependency @lokalise/node-api to v14.8.0 (#25651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 14:11:04 +02:00
renovate[bot]
65499db0cb Update babel monorepo to v7.27.3 (#25650)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 14:27:05 +03:00
renovate[bot]
11a1eabf61 Update rspack monorepo to v1.3.12 (#25649)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 14:26:40 +03:00
ildar170975
b30fa122ba Revert #25027 "more-info-camera: disable download_snapshot if idle" (#25643)
remove a check for "idle"
2025-05-30 10:59:03 +03:00
ildar170975
6730d08b85 Map card: add prefix & suffix for "label_mode: attribute" (#25033)
* added prefix & suffix

* added prefix & suffix

* added prefix & suffix

* added prefix & suffix

* added prefix & suffix

* remove prefix, rename suffix -> unit

* remove prefix, rename suffix -> unit

* remove prefix, rename suffix -> unit

* remove prefix, rename suffix -> unit

* remove prefix, rename suffix -> unit
2025-05-30 10:56:35 +03:00
ildar170975
67003d6fd1 Add cyrilic letters to slugify() (#25647)
* add cyrilic

* Update src/common/string/slugify.ts

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-05-30 05:38:45 +00:00
Petar Petrov
414d46be65 Add device button on the Z-Wave controller's device page (#25636) 2025-05-29 15:29:34 +03:00
Petar Petrov
1485d1a1de Fix Z-WaveJS device count in dashboard (#25635) 2025-05-29 15:29:24 +03:00
Ville Skyttä
fd13e41524 Spelling fixes (#25638) 2025-05-29 10:48:50 +02:00
Petar Petrov
77f7ca0368 Use theme variables for network graph labels (#25634) 2025-05-29 10:05:26 +02:00
Ville Skyttä
7471250a07 Fix Zigbee capitalization in manage device button (#25637) 2025-05-29 07:59:58 +00:00
karwosts
8b0a63d791 Cleanup some styling on disabled entity picker (#25632) 2025-05-29 08:53:30 +03:00
renovate[bot]
57ffa814ed Update dependency @octokit/rest to v22 (#25633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-29 08:51:54 +03:00
Paul Bottein
16e20456e2 Put item at the top of picker result if there is an exact match with entity id (#25625) 2025-05-28 22:33:42 +02:00
Paul Bottein
9c0ce41ebb Improve search in add automation element dialog (#25626)
* Improve search in add automation element dialog

* Remove unexpected import

* Take min character search into account
2025-05-28 19:38:33 +02:00
Paul Bottein
b458a1d7c6 Improve action picker UI and search (#25525) 2025-05-28 15:03:17 +02:00
renovate[bot]
0eaeeb1141 Update dependency globals to v16.2.0 (#25624)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 14:51:35 +03:00
Paul Bottein
b7e63e697f Fix picker field height (#25623) 2025-05-28 14:07:22 +03:00
Paul Bottein
06db0f4b98 Fix missing helper for entity picker (#25622) 2025-05-28 14:06:45 +03:00
Paul Bottein
d33636c6fb Force narrow style for action, condition and trigger in flows (#25619) 2025-05-28 12:04:54 +02:00
Wendelin
bbb546159c Set markdown code line-height (#25618) 2025-05-28 10:04:54 +02:00
karwosts
e8fc36026a More error handling for preview flow (#25611)
* More error handling for preview flow

* await unsub
2025-05-28 07:04:03 +03:00
Petar Petrov
38f8c804af Fix for history graph with tiny values (#25612) 2025-05-27 20:46:03 +02:00
Petar Petrov
7c5bf26240 Fix duplicate legend items when comparing energy data (#25610) 2025-05-27 20:43:32 +02:00
Norbert Rittel
189067d14b Fix typo in restore_entity_id_selected::confirm_text (#25615) 2025-05-27 19:56:55 +02:00
Petar Petrov
e79e0f77b8 Navigate to newly added device (#25608) 2025-05-27 16:19:53 +02:00
Wendelin
b226e5c697 Fix font settings for button card (#25607) 2025-05-27 12:55:20 +02:00
Wendelin
52ad31601c Fix sidebar loading and demo (#25606) 2025-05-27 10:22:04 +02:00
Petar Petrov
cba3e4df7f Fix double history graphs for a disabled entity (#25604) 2025-05-27 09:08:58 +02:00
Paul Bottein
3532cfa974 Fix duplicated items in strategy editor (#25600) 2025-05-26 19:21:44 +02:00
44 changed files with 642 additions and 596 deletions

View File

@@ -1 +1 @@
yarn run lint-staged --relative --shell "/bin/bash"
yarn run lint-staged --relative

View File

@@ -26,7 +26,7 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "7.27.1",
"@babel/runtime": "7.27.4",
"@braintree/sanitize-url": "7.1.1",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/commands": "6.8.1",
@@ -34,7 +34,7 @@
"@codemirror/legacy-modes": "6.5.1",
"@codemirror/search": "6.5.11",
"@codemirror/state": "6.5.2",
"@codemirror/view": "6.36.8",
"@codemirror/view": "6.37.1",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.18.0",
"@formatjs/intl-displaynames": "6.8.11",
@@ -111,7 +111,7 @@
"fuse.js": "7.1.0",
"google-timezones-json": "1.2.0",
"gulp-zopfli-green": "6.0.2",
"hls.js": "1.6.2",
"hls.js": "1.6.4",
"home-assistant-js-websocket": "9.5.0",
"idb-keyval": "6.2.2",
"intl-messageformat": "10.7.16",
@@ -149,20 +149,20 @@
"xss": "1.0.15"
},
"devDependencies": {
"@babel/core": "7.27.1",
"@babel/core": "7.27.4",
"@babel/helper-define-polyfill-provider": "0.6.4",
"@babel/plugin-transform-runtime": "7.27.1",
"@babel/plugin-transform-runtime": "7.27.4",
"@babel/preset-env": "7.27.2",
"@bundle-stats/plugin-webpack-filter": "4.20.1",
"@lokalise/node-api": "14.7.0",
"@bundle-stats/plugin-webpack-filter": "4.20.2",
"@lokalise/node-api": "14.8.0",
"@octokit/auth-oauth-device": "8.0.1",
"@octokit/plugin-retry": "8.0.1",
"@octokit/rest": "21.1.1",
"@octokit/rest": "22.0.0",
"@rsdoctor/rspack-plugin": "1.1.2",
"@rspack/cli": "1.3.11",
"@rspack/core": "1.3.11",
"@rspack/cli": "1.3.12",
"@rspack/core": "1.3.12",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.21",
"@types/chromecast-caf-receiver": "6.0.22",
"@types/chromecast-caf-sender": "1.0.11",
"@types/color-name": "2.0.0",
"@types/glob": "8.1.0",
@@ -184,7 +184,7 @@
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.3",
"del": "8.0.0",
"eslint": "9.27.0",
"eslint": "9.28.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "10.1.5",
"eslint-import-resolver-webpack": "0.13.10",
@@ -196,7 +196,7 @@
"fancy-log": "2.0.0",
"fs-extra": "11.3.0",
"glob": "11.0.2",
"gulp": "5.0.0",
"gulp": "5.0.1",
"gulp-brotli": "3.0.0",
"gulp-json-transform": "0.5.0",
"gulp-rename": "2.0.0",
@@ -204,7 +204,7 @@
"husky": "9.1.7",
"jsdom": "26.1.0",
"jszip": "3.10.1",
"lint-staged": "15.5.2",
"lint-staged": "16.1.0",
"lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2",
"lodash.template": "4.5.0",
@@ -218,7 +218,7 @@
"terser-webpack-plugin": "5.3.14",
"ts-lit-plugin": "2.0.2",
"typescript": "5.8.3",
"typescript-eslint": "8.32.1",
"typescript-eslint": "8.33.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.1.4",
"webpack-stats-plugin": "1.1.3",
@@ -232,7 +232,7 @@
"clean-css": "5.3.3",
"@lit/reactive-element": "2.1.0",
"@fullcalendar/daygrid": "6.1.17",
"globals": "16.1.0",
"globals": "16.2.0",
"tslib": "2.8.1",
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch"
},

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20250528.0"
version = "20250430.0"
license = "Apache-2.0"
license-files = ["LICENSE*"]
description = "The Home Assistant frontend"

View File

@@ -1,9 +1,19 @@
// https://gist.github.com/hagemann/382adfc57adbd5af078dc93feef01fe1
export const slugify = (value: string, delimiter = "_") => {
const a =
"àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìıİłḿñńǹňôöòóœøōõőŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·";
const b = `aaaaaaaaaacccddeeeeeeeegghiiiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz${delimiter}`;
"àáâäæãåāăąабçćčđďдèéêëēėęěеёэфğǵгḧхîïíīįìıİийкłлḿмñńǹňнôöòóœøōõőоṕпŕřрßśšşșсťțтûüùúūǘůűųувẃẍÿýыžźżз·";
const b = `aaaaaaaaaaabcccdddeeeeeeeeeeefggghhiiiiiiiiijkllmmnnnnnoooooooooopprrrsssssstttuuuuuuuuuuvwxyyyzzzz${delimiter}`;
const p = new RegExp(a.split("").join("|"), "g");
const complex_cyrillic = {
ж: "zh",
х: "kh",
ц: "ts",
ч: "ch",
ш: "sh",
щ: "shch",
ю: "iu",
я: "ia",
};
let slugified;
@@ -14,6 +24,7 @@ export const slugify = (value: string, delimiter = "_") => {
.toString()
.toLowerCase()
.replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters
.replace(/[а-я]/g, (c) => complex_cyrillic[c] || "") // Replace some cyrillic characters
.replace(/(\d),(?=\d)/g, "$1") // Remove Commas between numbers
.replace(/[^a-z0-9]+/g, delimiter) // Replace all non-word characters
.replace(new RegExp(`(${delimiter})\\1+`, "g"), "$1") // Replace multiple delimiters with single delimiter

View File

@@ -494,6 +494,13 @@ export class HaChartBase extends LitElement {
smooth: false,
},
bar: { itemStyle: { barBorderWidth: 1.5 } },
graph: {
label: {
color: style.getPropertyValue("--primary-text-color"),
textBorderColor: style.getPropertyValue("--primary-background-color"),
textBorderWidth: 2,
},
},
categoryAxis: {
axisLine: { show: false },
axisTick: { show: false },

View File

@@ -740,6 +740,7 @@ export class HaDataTable extends LitElement {
}, {});
const groupedItems: DataTableRowData[] = [];
Object.entries(sorted).forEach(([groupName, rows]) => {
const collapsed = collapsedGroups.includes(groupName);
groupedItems.push({
append: true,
selectable: false,
@@ -751,9 +752,10 @@ export class HaDataTable extends LitElement {
>
<ha-icon-button
.path=${mdiChevronUp}
class=${collapsedGroups.includes(groupName)
? "collapsed"
: ""}
.label=${this.hass.localize(
`ui.components.data-table.${collapsed ? "expand" : "collapse"}`
)}
class=${collapsed ? "collapsed" : ""}
>
</ha-icon-button>
${groupName === UNDEFINED_GROUP_KEY

View File

@@ -72,7 +72,9 @@ export class HaGenericPicker extends LitElement {
protected render() {
return html`
${this.label ? html`<label>${this.label}</label>` : nothing}
${this.label
? html`<label ?disabled=${this.disabled}>${this.label}</label>`
: nothing}
<div class="container">
${!this._opened
? html`
@@ -116,7 +118,9 @@ export class HaGenericPicker extends LitElement {
private _renderHelper() {
return this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
? html`<ha-input-helper-text .disabled=${this.disabled}
>${this.helper}</ha-input-helper-text
>`
: nothing;
}
@@ -165,6 +169,9 @@ export class HaGenericPicker extends LitElement {
position: relative;
display: block;
}
label[disabled] {
color: var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.6));
}
label {
display: block;
margin: 0 0 8px;

View File

@@ -1,9 +1,11 @@
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
@customElement("ha-input-helper-text")
class InputHelperText extends LitElement {
@property({ type: Boolean, reflect: true }) disabled = false;
protected render(): TemplateResult {
return html`<slot></slot>`;
}
@@ -18,6 +20,9 @@ class InputHelperText extends LitElement {
padding-inline-start: 16px;
padding-inline-end: 16px;
}
:host([disabled]) {
color: var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.6));
}
`;
}

View File

@@ -85,7 +85,9 @@ class HaMultiTextField extends LitElement {
</ha-button>
</div>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
? html`<ha-input-helper-text .disabled=${this.disabled}
>${this.helper}</ha-input-helper-text
>`
: nothing}
`;
}

View File

@@ -44,7 +44,7 @@ const createPanelNavigationItem = (hass: HomeAssistant, panel: PanelInfo) => ({
path: `/${panel.url_path}`,
icon: panel.icon ?? "mdi:view-dashboard",
title:
panel.url_path === hass.defaultPanel
panel.url_path === hass.sidebar.defaultPanel
? hass.localize("panel.states")
: hass.localize(`panel.${panel.title}`) ||
panel.title ||

View File

@@ -88,6 +88,12 @@ export class HaPickerField extends LitElement {
static get styles(): CSSResultGroup {
return [
css`
ha-combo-box-item[disabled] {
background-color: var(
--mdc-text-field-disabled-fill-color,
whitesmoke
);
}
ha-combo-box-item {
background-color: var(--mdc-text-field-fill-color, whitesmoke);
border-radius: 4px;
@@ -106,6 +112,12 @@ export class HaPickerField extends LitElement {
}
/* Add Similar focus style as the text field */
ha-combo-box-item[disabled]:after {
background-color: var(
--mdc-text-field-disabled-line-color,
rgba(0, 0, 0, 0.42)
);
}
ha-combo-box-item:after {
display: block;
content: "";

View File

@@ -50,6 +50,7 @@ import type { HaMdListItem } from "./ha-md-list-item";
import "./ha-spinner";
import "./ha-svg-icon";
import "./user/ha-user-badge";
import { DEFAULT_PANEL } from "../data/panel";
const SHOW_AFTER_SPACER = ["config", "developer-tools"];
@@ -140,9 +141,9 @@ const defaultPanelSorter = (
export const computePanels = memoizeOne(
(
panels: HomeAssistant["panels"],
defaultPanel: HomeAssistant["defaultPanel"],
panelsOrder: string[],
hiddenPanels: string[],
defaultPanel: HomeAssistant["sidebar"]["defaultPanel"],
panelsOrder: HomeAssistant["sidebar"]["panelOrder"],
hiddenPanels: HomeAssistant["sidebar"]["hiddenPanels"],
locale: HomeAssistant["locale"]
): [PanelInfo[], PanelInfo[]] => {
if (!panels) {
@@ -195,10 +196,6 @@ class HaSidebar extends SubscribeMixin(LitElement) {
@state() private _issuesCount = 0;
@state() private _panelOrder?: string[];
@state() private _hiddenPanels?: string[];
private _mouseLeaveTimeout?: number;
private _tooltipHideTimeout?: number;
@@ -213,18 +210,32 @@ class HaSidebar extends SubscribeMixin(LitElement) {
this.hass.connection,
"sidebar",
({ value }) => {
this._panelOrder = value?.panelOrder;
this._hiddenPanels = value?.hiddenPanels;
let panelOrder = value?.panelOrder;
let hiddenPanels = value?.hiddenPanels;
let defaultPanel = value?.defaultPanel;
// fallback to old localStorage values
if (!this._panelOrder) {
if (!panelOrder) {
const storedOrder = localStorage.getItem("sidebarPanelOrder");
this._panelOrder = storedOrder ? JSON.parse(storedOrder) : [];
panelOrder = storedOrder ? JSON.parse(storedOrder) : [];
}
if (!this._hiddenPanels) {
if (!hiddenPanels) {
const storedHidden = localStorage.getItem("sidebarHiddenPanels");
this._hiddenPanels = storedHidden ? JSON.parse(storedHidden) : [];
hiddenPanels = storedHidden ? JSON.parse(storedHidden) : [];
}
if (!defaultPanel) {
const storedDefault = localStorage.getItem("defaultPanel");
defaultPanel = storedDefault
? JSON.parse(storedDefault)
: DEFAULT_PANEL;
}
fireEvent(this, "hass-set-sidebar-data", {
...value,
defaultPanel: defaultPanel as string,
panelOrder: panelOrder as string[],
hiddenPanels: hiddenPanels as string[],
});
}
),
subscribeNotifications(this.hass.connection, (notifications) => {
@@ -275,8 +286,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
changedProps.has("_updatesCount") ||
changedProps.has("_issuesCount") ||
changedProps.has("_notifications") ||
changedProps.has("_hiddenPanels") ||
changedProps.has("_panelOrder")
(changedProps.has("hass") &&
changedProps.get("hass")?.sidebar !== this.hass.sidebar)
) {
return true;
}
@@ -295,7 +306,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
hass.localize !== oldHass.localize ||
hass.locale !== oldHass.locale ||
hass.states !== oldHass.states ||
hass.defaultPanel !== oldHass.defaultPanel ||
hass.sidebar !== oldHass.sidebar ||
hass.connected !== oldHass.connected
);
}
@@ -365,7 +376,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
}
private _renderAllPanels(selectedPanel: string) {
if (!this._panelOrder || !this._hiddenPanels) {
if (!this.hass.sidebar.panelOrder || !this.hass.sidebar.hiddenPanels) {
return html`
<ha-fade-in .delay=${500}
><ha-spinner size="small"></ha-spinner
@@ -375,9 +386,9 @@ class HaSidebar extends SubscribeMixin(LitElement) {
const [beforeSpacer, afterSpacer] = computePanels(
this.hass.panels,
this.hass.defaultPanel,
this._panelOrder,
this._hiddenPanels,
this.hass.sidebar.defaultPanel,
this.hass.sidebar.panelOrder,
this.hass.sidebar.hiddenPanels,
this.hass.locale
);
@@ -402,11 +413,11 @@ class HaSidebar extends SubscribeMixin(LitElement) {
return panels.map((panel) =>
this._renderPanel(
panel.url_path,
panel.url_path === this.hass.defaultPanel
panel.url_path === this.hass.sidebar.defaultPanel
? panel.title || this.hass.localize("panel.states")
: this.hass.localize(`panel.${panel.title}`) || panel.title,
panel.icon,
panel.url_path === this.hass.defaultPanel && !panel.icon
panel.url_path === this.hass.sidebar.defaultPanel && !panel.icon
? PANEL_ICONS.lovelace
: panel.url_path in PANEL_ICONS
? PANEL_ICONS[panel.url_path]
@@ -626,12 +637,15 @@ class HaSidebar extends SubscribeMixin(LitElement) {
this._tooltipHideTimeout = undefined;
}
const tooltip = this._tooltip;
const listbox = this.shadowRoot!.querySelector("ha-md-list")!;
let top = item.offsetTop + 11;
if (listbox.contains(item)) {
top += listbox.offsetTop;
top -= listbox.scrollTop;
}
const allListbox = this.shadowRoot!.querySelectorAll("ha-md-list")!;
const listbox = [...allListbox].find((lb) => lb.contains(item));
const top =
item.offsetTop +
11 +
(listbox?.offsetTop ?? 0) -
(listbox?.scrollTop ?? 0);
tooltip.innerText = (
item.querySelector(".item-text") as HTMLElement
).innerText;

View File

@@ -12,6 +12,8 @@ class HaEntityMarker extends LitElement {
@property({ attribute: "entity-name" }) public entityName?: string;
@property({ attribute: "entity-unit" }) public entityUnit?: string;
@property({ attribute: "entity-picture" }) public entityPicture?: string;
@property({ attribute: "entity-color" }) public entityColor?: string;
@@ -37,7 +39,16 @@ class HaEntityMarker extends LitElement {
.hass=${this.hass}
.stateObj=${this.hass?.states[this.entityId]}
></ha-state-icon>`
: this.entityName}
: !this.entityUnit
? this.entityName
: html`
${this.entityName}
<span
class="unit"
style="display: ${this.entityUnit ? "initial" : "none"}"
>${this.entityUnit}</span
>
`}
</div>
`;
}
@@ -72,6 +83,9 @@ class HaEntityMarker extends LitElement {
height: 100%;
width: 100%;
}
.unit {
margin-left: 2px;
}
`;
}

View File

@@ -56,6 +56,7 @@ export interface HaMapEntity {
color: string;
label_mode?: "name" | "state" | "attribute" | "icon";
attribute?: string;
unit?: string;
name?: string;
focus?: boolean;
}
@@ -549,6 +550,12 @@ export class HaMap extends ReactiveElement {
typeof entity !== "string" && entity.label_mode === "icon";
entityMarker.entityId = getEntityId(entity);
entityMarker.entityName = entityName;
entityMarker.entityUnit =
typeof entity !== "string" &&
entity.unit &&
entity.label_mode === "attribute"
? entity.unit
: "";
entityMarker.entityPicture =
entityPicture && (typeof entity === "string" || !entity.label_mode)
? this.hass.hassUrl(entityPicture)

View File

@@ -8,6 +8,7 @@ export interface CoreFrontendUserData {
export interface SidebarFrontendUserData {
panelOrder: string[];
hiddenPanels: string[];
defaultPanel?: string;
}
declare global {

View File

@@ -1,4 +1,3 @@
import { fireEvent } from "../common/dom/fire_event";
import type { HomeAssistant, PanelInfo } from "../types";
/** Panel to show when no panel is picked. */
@@ -10,16 +9,9 @@ export const getStorageDefaultPanelUrlPath = (): string => {
return defaultPanel ? JSON.parse(defaultPanel) : DEFAULT_PANEL;
};
export const setDefaultPanel = (
element: HTMLElement,
urlPath: string
): void => {
fireEvent(element, "hass-default-panel", { defaultPanel: urlPath });
};
export const getDefaultPanel = (hass: HomeAssistant): PanelInfo =>
hass.panels[hass.defaultPanel]
? hass.panels[hass.defaultPanel]
hass.panels[hass.sidebar.defaultPanel]
? hass.panels[hass.sidebar.defaultPanel]
: hass.panels[DEFAULT_PANEL];
export const getPanelNameTranslationKey = (panel: PanelInfo) => {

View File

@@ -6,6 +6,7 @@ const HAS_CUSTOM_PREVIEW = ["generic_camera", "template"];
export interface GenericPreview {
state: string;
attributes: Record<string, any>;
error?: string;
}
export const subscribePreviewGeneric = (

View File

@@ -58,6 +58,11 @@ export class FlowPreviewGeneric extends LitElement {
}
private _setPreview = (preview: GenericPreview) => {
if (preview.error) {
this._error = preview.error;
this._preview = undefined;
return;
}
const now = new Date().toISOString();
this._preview = {
entity_id: `${this.stepId}.___flow_preview___`,
@@ -80,6 +85,7 @@ export class FlowPreviewGeneric extends LitElement {
if (this.flowType !== "config_flow" && this.flowType !== "options_flow") {
return;
}
this._error = undefined;
try {
this._unsub = subscribePreviewGeneric(
this.hass,
@@ -89,6 +95,7 @@ export class FlowPreviewGeneric extends LitElement {
this.stepData,
this._setPreview
);
await this._unsub;
fireEvent(this, "set-flow-errors", { errors: {} });
} catch (err: any) {
if (typeof err.message === "string") {

View File

@@ -235,9 +235,13 @@ class StepFlowCreateEntry extends LitElement {
fireEvent(this, "flow-update", { step: undefined });
if (this.step.result && this.navigateToResult) {
navigate(
`/config/integrations/integration/${this.step.result.domain}#config_entry=${this.step.result.entry_id}`
);
if (this.devices.length === 1) {
navigate(`/config/devices/device/${this.devices[0].id}`);
} else {
navigate(
`/config/integrations/integration/${this.step.result.domain}#config_entry=${this.step.result.entry_id}`
);
}
}
}

View File

@@ -45,8 +45,7 @@ class MoreInfoCamera extends LitElement {
<ha-progress-button
@click=${this._downloadSnapshot}
.progress=${this._waiting}
.disabled=${this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === "idle"}
.disabled=${this.stateObj.state === UNAVAILABLE}
>
${this.hass.localize(
"ui.dialogs.more_info_control.camera.download_snapshot"

View File

@@ -96,7 +96,7 @@ class DialogEditSidebar extends LitElement {
const [beforeSpacer, afterSpacer] = computePanels(
this.hass.panels,
this.hass.defaultPanel,
this.hass.sidebar.defaultPanel,
this._order,
this._hidden,
this.hass.locale
@@ -109,12 +109,12 @@ class DialogEditSidebar extends LitElement {
].map((panel) => ({
value: panel.url_path,
label:
panel.url_path === this.hass.defaultPanel
panel.url_path === this.hass.sidebar.defaultPanel
? panel.title || this.hass.localize("panel.states")
: this.hass.localize(`panel.${panel.title}`) || panel.title || "?",
icon: panel.icon || undefined,
iconPath:
panel.url_path === this.hass.defaultPanel && !panel.icon
panel.url_path === this.hass.sidebar.defaultPanel && !panel.icon
? PANEL_ICONS.lovelace
: panel.url_path in PANEL_ICONS
? PANEL_ICONS[panel.url_path]
@@ -195,6 +195,7 @@ class DialogEditSidebar extends LitElement {
await saveFrontendUserData(this.hass.connection, "sidebar", {
panelOrder: this._order!,
hiddenPanels: this._hidden!,
defaultPanel: this.hass.sidebar.defaultPanel,
});
} catch (err: any) {
this._error = err.message || err;

View File

@@ -497,9 +497,9 @@ export class HAFullCalendar extends LitElement {
ha-fab {
position: absolute;
bottom: 32px;
right: 32px;
inset-inline-end: 32px;
bottom: 16px;
right: 16px;
inset-inline-end: 16px;
inset-inline-start: initial;
z-index: 1;
}

View File

@@ -233,6 +233,8 @@ export class CloudLogin extends LitElement {
text: this.hass.localize(
"ui.panel.config.cloud.login.cloud_pipeline_text"
),
confirmText: this.hass.localize("ui.common.yes"),
dismissText: this.hass.localize("ui.common.no"),
})
) {
setAssistPipelinePreferred(this.hass, result.cloud_pipeline);

View File

@@ -4,6 +4,7 @@ import {
mdiDeleteForever,
mdiHospitalBox,
mdiInformation,
mdiPlus,
mdiUpload,
mdiWrench,
} from "@mdi/js";
@@ -13,6 +14,7 @@ import {
fetchZwaveIntegrationSettings,
fetchZwaveIsAnyOTAFirmwareUpdateInProgress,
fetchZwaveIsNodeFirmwareUpdateInProgress,
fetchZwaveNetworkStatus,
fetchZwaveNodeStatus,
} from "../../../../../../data/zwave_js";
import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box";
@@ -24,6 +26,7 @@ import { showZWaveJSRemoveFailedNodeDialog } from "../../../../integrations/inte
import { showZWaveJSUpdateFirmwareNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-update-firmware-node";
import type { DeviceAction } from "../../../ha-config-device-page";
import { showZWaveJSHardResetControllerDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-hard-reset-controller";
import { showZWaveJSAddNodeDialog } from "../../../../integrations/integration-panels/zwave_js/add-node/show-dialog-zwave_js-add-node";
export const getZwaveDeviceActions = async (
el: HTMLElement,
@@ -160,6 +163,19 @@ export const getZwaveDeviceActions = async (
}
if (nodeStatus.is_controller_node) {
const networkStatus = await fetchZwaveNetworkStatus(hass, {
entry_id: entryId,
});
actions.unshift({
label: hass.localize("ui.panel.config.zwave_js.common.add_node"),
icon: mdiPlus,
action: async () => {
showZWaveJSAddNodeDialog(el, {
entry_id: entryId,
longRangeSupported: networkStatus.controller?.supports_long_range,
});
},
});
actions.push({
label: hass.localize(
"ui.panel.config.zwave_js.device_info.hard_reset_controller"

View File

@@ -163,6 +163,7 @@ export class HaIntegrationCard extends LitElement {
: "custom"}"
>
<ha-tooltip
hoist
.placement=${computeRTL(this.hass) ? "right" : "left"}
.content=${this.hass.localize(
this.manifest.overwrites_built_in
@@ -177,6 +178,7 @@ export class HaIntegrationCard extends LitElement {
${this.manifest && this.manifest.iot_class?.startsWith("cloud_")
? html`<div class="icon cloud">
<ha-tooltip
hoist
.placement=${computeRTL(this.hass) ? "right" : "left"}
.content=${this.hass.localize(
"ui.panel.config.integrations.config_entry.depends_on_cloud"
@@ -191,6 +193,7 @@ export class HaIntegrationCard extends LitElement {
!this.items.every((itm) => itm.source === "system")
? html`<div class="icon yaml">
<ha-tooltip
hoist
.placement=${computeRTL(this.hass) ? "right" : "left"}
.content=${this.hass.localize(
"ui.panel.config.integrations.config_entry.no_config_flow"

View File

@@ -133,8 +133,11 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
if (ERROR_STATES.includes(this._configEntry.state)) {
return this._renderErrorScreen();
}
const provisioningDevices =
this._provisioningEntries?.filter((entry) => !entry.nodeId).length ?? 0;
const notReadyDevices =
this._network?.controller.nodes.filter((node) => !node.ready).length ?? 0;
(this._network?.controller.nodes.filter((node) => !node.ready).length ??
0) + provisioningDevices;
return html`
<hass-tabs-subpage
@@ -182,7 +185,9 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
${this.hass.localize(
`ui.panel.config.zwave_js.dashboard.devices`,
{
count: this._network.controller.nodes.length,
count:
this._network.controller.nodes.length +
provisioningDevices,
}
)}
${notReadyDevices > 0

View File

@@ -13,10 +13,11 @@ import type {
LovelaceDashboardCreateParams,
LovelaceDashboardMutableParams,
} from "../../../../data/lovelace/dashboard";
import { DEFAULT_PANEL, setDefaultPanel } from "../../../../data/panel";
import { DEFAULT_PANEL } from "../../../../data/panel";
import { haStyleDialog } from "../../../../resources/styles";
import type { HomeAssistant } from "../../../../types";
import type { LovelaceDashboardDetailsDialogParams } from "./show-dialog-lovelace-dashboard-detail";
import { saveFrontendUserData } from "../../../../data/frontend";
@customElement("dialog-lovelace-dashboard-detail")
export class DialogLovelaceDashboardDetail extends LitElement {
@@ -59,7 +60,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
if (!this._params || !this._data) {
return nothing;
}
const defaultPanelUrlPath = this.hass.defaultPanel;
const defaultPanelUrlPath = this.hass.sidebar.defaultPanel;
const titleInvalid = !this._data.title || !this._data.title.trim();
return html`
@@ -249,15 +250,17 @@ export class DialogLovelaceDashboardDetail extends LitElement {
};
}
private _toggleDefault() {
private async _toggleDefault() {
const urlPath = this._params?.urlPath;
if (!urlPath) {
return;
}
setDefaultPanel(
this,
urlPath === this.hass.defaultPanel ? DEFAULT_PANEL : urlPath
);
await saveFrontendUserData(this.hass!.connection, "sidebar", {
panelOrder: this.hass!.sidebar.panelOrder,
hiddenPanels: this.hass!.sidebar.hiddenPanels,
defaultPanel:
urlPath === this.hass.sidebar.defaultPanel ? DEFAULT_PANEL : urlPath,
});
}
private async _updateDashboard() {

View File

@@ -255,7 +255,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
const defaultMode = (
this.hass.panels?.lovelace?.config as LovelacePanelConfig
).mode;
const defaultUrlPath = this.hass.defaultPanel;
const defaultUrlPath = this.hass.sidebar.defaultPanel;
const isDefault = defaultUrlPath === "lovelace";
const result: DataTableItem[] = [
{

View File

@@ -384,15 +384,22 @@ export class HuiAreaCard
areaSensorEntityId = area.humidity_entity_id;
break;
}
const areaEntity = areaSensorEntityId
? this.hass.states[areaSensorEntityId]
: undefined;
const areaEntity =
areaSensorEntityId &&
this.hass.states[areaSensorEntityId] &&
!isUnavailableState(this.hass.states[areaSensorEntityId].state)
? this.hass.states[areaSensorEntityId]
: undefined;
if (
areaEntity ||
entitiesByDomain[domain].some(
(entity) => entity.attributes.device_class === deviceClass
)
) {
let value = areaEntity
? this.hass.formatEntityState(areaEntity)
: this._average(domain, deviceClass);
if (!value) value = "—";
sensors.push(html`
<div class="sensor">
<ha-domain-icon
@@ -400,9 +407,7 @@ export class HuiAreaCard
.domain=${domain}
.deviceClass=${deviceClass}
></ha-domain-icon>
${areaEntity
? this.hass.formatEntityState(areaEntity)
: this._average(domain, deviceClass)}
${value}
</div>
`);
}

View File

@@ -301,7 +301,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: var(--ha-line-height-expanded);
line-height: var(--ha-line-height-condensed);
}
.value {

View File

@@ -45,6 +45,7 @@ export const DEFAULT_ZOOM = 14;
interface MapEntityConfig extends EntityConfig {
label_mode?: "state" | "attribute" | "name";
attribute?: string;
unit?: string;
focus?: boolean;
}
@@ -52,6 +53,7 @@ interface GeoEntity {
entity_id: string;
label_mode?: "state" | "attribute" | "name" | "icon";
attribute?: string;
unit?: string;
focus: boolean;
}
@@ -430,6 +432,7 @@ class HuiMapCard extends LitElement implements LovelaceCard {
entity_id: stateObj.entity_id,
label_mode: sourceObj?.label_mode ?? allSource?.label_mode,
attribute: sourceObj?.attribute ?? allSource?.attribute,
unit: sourceObj?.unit ?? allSource?.unit,
focus: sourceObj
? (sourceObj.focus ?? true)
: (allSource?.focus ?? true),
@@ -446,6 +449,7 @@ class HuiMapCard extends LitElement implements LovelaceCard {
color: this._getColor(entityConf.entity),
label_mode: entityConf.label_mode,
attribute: entityConf.attribute,
unit: entityConf.unit,
focus: entityConf.focus,
name: entityConf.name,
})),

View File

@@ -323,6 +323,7 @@ interface GeoLocationSourceConfig {
source: string;
label_mode?: "name" | "state" | "attribute" | "icon";
attribute?: string;
unit?: string;
focus?: boolean;
}

View File

@@ -40,6 +40,7 @@ export const mapEntitiesConfigStruct = union([
entity: string(),
label_mode: optional(string()),
attribute: optional(string()),
unit: optional(string()),
focus: optional(boolean()),
name: optional(string()),
}),
@@ -51,6 +52,7 @@ const geoSourcesConfigStruct = union([
source: string(),
label_mode: optional(string()),
attribute: optional(string()),
unit: optional(string()),
focus: optional(boolean()),
}),
string(),

View File

@@ -139,7 +139,7 @@ export class HuiDialogSelectDashboard extends LitElement {
...(this._params!.dashboards || (await fetchDashboards(this.hass))),
];
const currentPath = this._fromUrlPath || this.hass.defaultPanel;
const currentPath = this._fromUrlPath || this.hass.sidebar.defaultPanel;
for (const dashboard of this._dashboards!) {
if (dashboard.url_path !== currentPath) {
this._toUrlPath = dashboard.url_path;

View File

@@ -77,7 +77,7 @@ export class HuiDialogSelectView extends LitElement {
"ui.panel.lovelace.editor.select_view.dashboard_label"
)}
.disabled=${!this._dashboards.length}
.value=${this._urlPath || this.hass.defaultPanel}
.value=${this._urlPath || this.hass.sidebar.defaultPanel}
@selected=${this._dashboardChanged}
@closed=${stopPropagation}
fixedMenuPosition

View File

@@ -1109,6 +1109,16 @@ class HUIRoot extends LitElement {
sl-tab[aria-selected="true"] .edit-icon {
display: inline-flex;
}
sl-tab::part(base) {
padding-inline-start: var(
--ha-tab-padding-start,
var(--sl-spacing-large)
);
padding-inline-end: var(
--ha-tab-padding-end,
var(--sl-spacing-large)
);
}
sl-tab::part(base) {
padding-top: calc((var(--header-height) - 20px) / 2);
padding-bottom: calc((var(--header-height) - 20px) / 2 - 2px);

View File

@@ -6,8 +6,8 @@ import "../../components/ha-select";
import "../../components/ha-settings-row";
import type { LovelaceDashboard } from "../../data/lovelace/dashboard";
import { fetchDashboards } from "../../data/lovelace/dashboard";
import { setDefaultPanel } from "../../data/panel";
import type { HomeAssistant } from "../../types";
import { saveFrontendUserData } from "../../data/frontend";
@customElement("ha-pick-dashboard-row")
class HaPickDashboardRow extends LitElement {
@@ -37,7 +37,7 @@ class HaPickDashboardRow extends LitElement {
"ui.panel.profile.dashboard.dropdown_label"
)}
.disabled=${!this._dashboards?.length}
.value=${this.hass.defaultPanel}
.value=${this.hass.sidebar.defaultPanel}
@selected=${this._dashboardChanged}
naturalMenuWidth
>
@@ -71,12 +71,16 @@ class HaPickDashboardRow extends LitElement {
this._dashboards = await fetchDashboards(this.hass);
}
private _dashboardChanged(ev) {
private async _dashboardChanged(ev) {
const urlPath = ev.target.value;
if (!urlPath || urlPath === this.hass.defaultPanel) {
if (!urlPath || urlPath === this.hass.sidebar.defaultPanel) {
return;
}
setDefaultPanel(this, urlPath);
await saveFrontendUserData(this.hass!.connection, "sidebar", {
panelOrder: this.hass!.sidebar.panelOrder,
hiddenPanels: this.hass!.sidebar.hiddenPanels,
defaultPanel: urlPath,
});
}
}

View File

@@ -167,6 +167,10 @@ class HaProfileSectionGeneral extends LitElement {
)}
</mwc-button>
</ha-settings-row>
<ha-pick-dashboard-row
.narrow=${this.narrow}
.hass=${this.hass}
></ha-pick-dashboard-row>
${this.hass.user!.is_admin
? html`
<ha-advanced-mode-row
@@ -200,10 +204,6 @@ class HaProfileSectionGeneral extends LitElement {
.narrow=${this.narrow}
.hass=${this.hass}
></ha-pick-theme-row>
<ha-pick-dashboard-row
.narrow=${this.narrow}
.hass=${this.hass}
></ha-pick-dashboard-row>
${this.hass.dockedSidebar !== "auto" || !this.narrow
? html`
<ha-force-narrow-row

View File

@@ -59,7 +59,11 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
services: null as any,
user: null as any,
panelUrl: (this as any)._panelUrl,
defaultPanel: DEFAULT_PANEL,
sidebar: {
defaultPanel: DEFAULT_PANEL,
hiddenPanels: [],
panelOrder: [],
},
language,
selectedLanguage: null,
locale: {

View File

@@ -7,20 +7,16 @@ interface DockSidebarParams {
dock: HomeAssistant["dockedSidebar"];
}
interface DefaultPanelParams {
defaultPanel: HomeAssistant["defaultPanel"];
}
declare global {
// for fire event
interface HASSDomEvents {
"hass-dock-sidebar": DockSidebarParams;
"hass-default-panel": DefaultPanelParams;
"hass-set-sidebar-data": HomeAssistant["sidebar"];
}
// for add event listener
interface HTMLElementEventMap {
"hass-dock-sidebar": HASSDomEvent<DockSidebarParams>;
"hass-default-panel": HASSDomEvent<DefaultPanelParams>;
"hass-set-sidebar-data": HASSDomEvent<HomeAssistant["sidebar"]>;
}
}
@@ -32,8 +28,10 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
this._updateHass({ dockedSidebar: ev.detail.dock });
storeState(this.hass!);
});
this.addEventListener("hass-default-panel", (ev) => {
this._updateHass({ defaultPanel: ev.detail.defaultPanel });
this.addEventListener("hass-set-sidebar-data", async (ev) => {
this._updateHass({
sidebar: ev.detail,
});
storeState(this.hass!);
});
}

View File

@@ -902,6 +902,8 @@
"hidden": "{number} hidden",
"clear": "Clear",
"ungrouped": "Ungrouped",
"collapse": "Collapse",
"expand": "Expand",
"settings": {
"header": "Customize",
"hide": "Hide column {title}",
@@ -1579,7 +1581,7 @@
"upload_in_progress": "A backup upload is currently in progress. The action will automatically proceed once the upload process is complete.",
"restore_in_progress": "A backup restore is currently in progress. The action will automatically proceed once the restore process is complete.",
"wait_for_backup": "Wait for the backup creation to finish",
"error_backup_state": "An error occured while getting the current backup state. Error: {error}",
"error_backup_state": "An error occurred while getting the current backup state. Error: {error}",
"wait_for_upload": "Wait for backup upload to finish",
"wait_for_restore": "Wait for backup restore to finish",
"reload": {
@@ -1782,7 +1784,7 @@
"buttons": {
"add": "Add devices via this device",
"remove": "Remove",
"manage": "Manage zigbee device",
"manage": "Manage Zigbee device",
"reconfigure": "Reconfigure",
"view_network": "View network"
},
@@ -2378,7 +2380,7 @@
},
"generate": {
"sync": {
"title": "Synchonization",
"title": "Synchronization",
"name": "Backup name",
"locations": "Locations",
"locations_description": "What locations you want to automatically backup to.",

View File

@@ -243,7 +243,11 @@ export interface HomeAssistant {
vibrate: boolean;
debugConnection: boolean;
dockedSidebar: "docked" | "always_hidden" | "auto";
defaultPanel: string;
sidebar: {
defaultPanel: string;
panelOrder: string[];
hiddenPanels: string[];
};
moreInfoEntityId: string | null;
user?: CurrentUser;
userData?: CoreFrontendUserData | null;

View File

@@ -8,7 +8,7 @@ const STORED_STATE = [
"debugConnection",
"suspendWhenHidden",
"enableShortcuts",
"defaultPanel",
"sidebar",
];
export function storeState(hass: HomeAssistant) {

849
yarn.lock

File diff suppressed because it is too large Load Diff