From 8fbcbb0b6854cb798515cdaf94d68f9f6613f01a Mon Sep 17 00:00:00 2001 From: Simon Lamon <32477463+silamon@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:51:36 +0100 Subject: [PATCH 01/18] Add label button to ha-filter-labels (#20251) --- src/components/ha-filter-labels.ts | 17 ++++++++++++++++- src/translations/en.json | 7 +++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/components/ha-filter-labels.ts b/src/components/ha-filter-labels.ts index 317ed7f57f..3213f22a6f 100644 --- a/src/components/ha-filter-labels.ts +++ b/src/components/ha-filter-labels.ts @@ -3,10 +3,12 @@ import "@material/mwc-menu/mwc-menu-surface"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { mdiPlus } from "@mdi/js"; import { computeCssColor } from "../common/color/compute-color"; import { fireEvent } from "../common/dom/fire_event"; import { LabelRegistryEntry, + createLabelRegistryEntry, subscribeLabelRegistry, } from "../data/label_registry"; import { SubscribeMixin } from "../mixins/subscribe-mixin"; @@ -16,6 +18,7 @@ import "./ha-check-list-item"; import "./ha-expansion-panel"; import "./ha-icon"; import "./ha-label"; +import { showLabelDetailDialog } from "../panels/config/labels/show-dialog-label-detail"; @customElement("ha-filter-labels") export class HaFilterLabels extends SubscribeMixin(LitElement) { @@ -84,6 +87,12 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) { ` : nothing} + ${this.expanded + ? html` + + ${this.hass.localize("ui.panel.config.labels.add_label")} + ` + : nothing} `; } @@ -92,11 +101,17 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) { setTimeout(() => { if (!this.expanded) return; this.renderRoot.querySelector("mwc-list")!.style.height = - `${this.clientHeight - 49}px`; + `${this.clientHeight - (49 + 48)}px`; }, 300); } } + private _addLabel() { + showLabelDetailDialog(this, { + createEntry: (values) => createLabelRegistryEntry(this.hass, values), + }); + } + private _expandedWillChange(ev) { this._shouldRender = ev.detail.expanded; } diff --git a/src/translations/en.json b/src/translations/en.json index 2977e7e8f4..8e282fba9d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1959,7 +1959,11 @@ "labels": { "caption": "Labels", "description": "Group devices and entities", - "headers": { "name": "Name", "icon": "Icon", "color": "Color" }, + "headers": { + "name": "Name", + "icon": "Icon", + "color": "Color" + }, "add_label": "Add label", "no_labels": "You don't have any labels", "introduction": "Labels can help you organize your areas, devices and entities. They can be used to filter in the UI, or use them as a target in automations.", @@ -5388,7 +5392,6 @@ "type": "View type", "type_warning_sections": "You can not change your view to use the 'sections' view type because migration is not supported yet. Start from scratch with a new view if you want to experiment with the 'sections' view.", "type_warning_others": "You can not change your view to an other type because migration is not supported yet. Start from scratch with a new view if you want to use another view type.", - "types": { "masonry": "Masonry (default)", "sidebar": "Sidebar", From 1300cffa3b41968e1228f9561a15e73de342c4b6 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 28 Mar 2024 23:13:51 +0100 Subject: [PATCH 02/18] Hide show all categories button is no categories (#20255) --- src/components/ha-filter-categories.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/ha-filter-categories.ts b/src/components/ha-filter-categories.ts index 9b5a7c539e..0555d06388 100644 --- a/src/components/ha-filter-categories.ts +++ b/src/components/ha-filter-categories.ts @@ -78,13 +78,15 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) { class="ha-scrollbar" activatable > - ${this.hass.localize( - "ui.panel.config.category.filter.show_all" - )} + ${this._categories.length > 0 + ? html`${this.hass.localize( + "ui.panel.config.category.filter.show_all" + )}` + : nothing} ${this._categories.map( (category) => html` Date: Fri, 29 Mar 2024 10:25:02 +0100 Subject: [PATCH 03/18] Fix search for labels and categories (#20262) --- src/components/ha-label-picker.ts | 4 ++-- src/panels/config/category/ha-category-picker.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/ha-label-picker.ts b/src/components/ha-label-picker.ts index 734df1081f..15b42c07b2 100644 --- a/src/components/ha-label-picker.ts +++ b/src/components/ha-label-picker.ts @@ -385,8 +385,8 @@ export class HaLabelPicker extends SubscribeMixin(LitElement) { const filteredItems = fuzzyFilterSort( filterString, - target.items?.filter((item) => - [NO_LABELS_ID, ADD_NEW_ID].includes(item.ignoreFilter) + target.items?.filter( + (item) => ![NO_LABELS_ID, ADD_NEW_ID].includes(item.label_id) ) || [] ); if (filteredItems.length === 0) { diff --git a/src/panels/config/category/ha-category-picker.ts b/src/panels/config/category/ha-category-picker.ts index 529db65b2c..16b15fe794 100644 --- a/src/panels/config/category/ha-category-picker.ts +++ b/src/panels/config/category/ha-category-picker.ts @@ -179,7 +179,9 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) { const filteredItems = fuzzyFilterSort( filterString, - target.items || [] + target.items?.filter( + (item) => ![NO_CATEGORIES_ID, ADD_NEW_ID].includes(item.category_id) + ) || [] ); if (filteredItems?.length === 0) { if (this.noAdd) { From 5dd029cc05a5e0981a5e219423a2d8db094d14cf Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 10:25:54 +0100 Subject: [PATCH 04/18] Add delete action in label overflow menu (#20261) --- src/panels/config/labels/ha-config-labels.ts | 24 +++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/panels/config/labels/ha-config-labels.ts b/src/panels/config/labels/ha-config-labels.ts index 9e779c6384..193dc4fc06 100644 --- a/src/panels/config/labels/ha-config-labels.ts +++ b/src/panels/config/labels/ha-config-labels.ts @@ -1,4 +1,4 @@ -import { mdiHelpCircle, mdiPlus } from "@mdi/js"; +import { mdiDelete, mdiHelpCircle, mdiPlus } from "@mdi/js"; import { LitElement, PropertyValues, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; @@ -11,6 +11,7 @@ import { import "../../../components/ha-fab"; import "../../../components/ha-icon-button"; import "../../../components/ha-relative-time"; +import "../../../components/ha-icon-overflow-menu"; import { LabelRegistryEntry, LabelRegistryEntryMutableParams, @@ -71,6 +72,26 @@ export class HaConfigLabels extends LitElement { filterable: true, grows: true, }, + actions: { + title: "", + width: "64px", + type: "overflow-menu", + template: (label) => html` + this._removeLabel(label), + warning: true, + }, + ]} + > + + `, + }, }; return columns; }); @@ -189,6 +210,7 @@ export class HaConfigLabels extends LitElement { }), dismissText: this.hass!.localize("ui.common.cancel"), confirmText: this.hass!.localize("ui.common.remove"), + destructive: true, })) ) { return false; From d1119a3b614eaaf1655c0c934f9a778646a554fd Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 11:16:28 +0100 Subject: [PATCH 05/18] Restore theme usage in stack card in panel view (#20264) --- src/panels/lovelace/cards/hui-stack-card.ts | 8 ++++---- src/panels/lovelace/views/hui-panel-view.ts | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/panels/lovelace/cards/hui-stack-card.ts b/src/panels/lovelace/cards/hui-stack-card.ts index 501e38cd7e..8fad6f7ca1 100644 --- a/src/panels/lovelace/cards/hui-stack-card.ts +++ b/src/panels/lovelace/cards/hui-stack-card.ts @@ -98,10 +98,10 @@ export abstract class HuiStackCard display: block; padding: 24px 16px 16px; } - :host { - --ha-card-border-radius: inherit !important; - --ha-card-border-width: inherit !important; - --ha-card-box-shadow: inherit !important; + #root { + --ha-card-border-radius: var(--restore-card-border-radius, inherit); + --ha-card-border-width: var(--restore-card-border-width, inherit); + --ha-card-box-shadow: var(--restore-card-border-shadow, inherit); } `; } diff --git a/src/panels/lovelace/views/hui-panel-view.ts b/src/panels/lovelace/views/hui-panel-view.ts index c65238af5a..a47eac437f 100644 --- a/src/panels/lovelace/views/hui-panel-view.ts +++ b/src/panels/lovelace/views/hui-panel-view.ts @@ -108,6 +108,7 @@ export class PanelView extends LitElement implements LovelaceViewElement { const card: LovelaceCard = this.cards[0]; card.isPanel = true; + card.toggleAttribute("no-border", true); if (this.isStrategy || !this.lovelace?.editMode) { card.editMode = false; @@ -116,6 +117,7 @@ export class PanelView extends LitElement implements LovelaceViewElement { } const wrapper = document.createElement("hui-card-options"); + wrapper.toggleAttribute("no-border", true); wrapper.hass = this.hass; wrapper.lovelace = this.lovelace; wrapper.path = [this.index!, 0]; @@ -130,9 +132,12 @@ export class PanelView extends LitElement implements LovelaceViewElement { :host { display: block; height: 100%; + --restore-card-border-radius: var(--ha-card-border-radius, 12px); + --restore-card-border-width: var(--ha-card-border-width, 1px); + --restore-card-box-shadow: var(--ha-card-box-shadow, none); } - * { + [no-border] { --ha-card-border-radius: 0; --ha-card-border-width: 0; --ha-card-box-shadow: none; From 520581c1650bf6b88074e7f7eeb17d7dc6323489 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 11:37:13 +0100 Subject: [PATCH 06/18] Reapply filters if entity registry change (#20265) --- src/data/entity_registry.ts | 8 +++---- .../config/automation/ha-automation-picker.ts | 22 +++++++++++++------ src/panels/config/scene/ha-scene-dashboard.ts | 8 +++++++ src/panels/config/script/ha-script-picker.ts | 8 +++++++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts index 9377c869cd..2ebfd15778 100644 --- a/src/data/entity_registry.ts +++ b/src/data/entity_registry.ts @@ -10,7 +10,7 @@ import { computeDomain } from "../common/entity/compute_domain"; export { subscribeEntityRegistryDisplay } from "./ws-entity_registry_display"; -type entityCategory = "config" | "diagnostic"; +type EntityCategory = "config" | "diagnostic"; export interface EntityRegistryDisplayEntry { entity_id: string; @@ -20,7 +20,7 @@ export interface EntityRegistryDisplayEntry { area_id?: string; labels: string[]; hidden?: boolean; - entity_category?: entityCategory; + entity_category?: EntityCategory; translation_key?: string; platform?: string; display_precision?: number; @@ -40,7 +40,7 @@ export interface EntityRegistryDisplayEntryResponse { hb?: boolean; dp?: number; }[]; - entity_categories: Record; + entity_categories: Record; } export interface EntityRegistryEntry { @@ -55,7 +55,7 @@ export interface EntityRegistryEntry { labels: string[]; disabled_by: "user" | "device" | "integration" | "config_entry" | null; hidden_by: Exclude; - entity_category: entityCategory | null; + entity_category: EntityCategory | null; has_entity_name: boolean; original_name?: string; unique_id: string; diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index a5fb93a70d..5057c1e4d1 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -18,6 +18,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, + PropertyValues, TemplateResult, css, html, @@ -38,13 +39,15 @@ import type { DataTableColumnContainer, RowClickedEvent, } from "../../../components/data-table/ha-data-table"; +import "../../../components/data-table/ha-data-table-labels"; import "../../../components/entity/ha-entity-toggle"; import "../../../components/ha-fab"; -import "../../../components/ha-filter-floor-areas"; import "../../../components/ha-filter-blueprints"; import "../../../components/ha-filter-categories"; import "../../../components/ha-filter-devices"; import "../../../components/ha-filter-entities"; +import "../../../components/ha-filter-floor-areas"; +import "../../../components/ha-filter-labels"; import "../../../components/ha-icon-button"; import "../../../components/ha-icon-overflow-menu"; import "../../../components/ha-svg-icon"; @@ -64,6 +67,10 @@ import { import { fullEntitiesContext } from "../../../data/context"; import { UNAVAILABLE } from "../../../data/entity"; import { EntityRegistryEntry } from "../../../data/entity_registry"; +import { + LabelRegistryEntry, + subscribeLabelRegistry, +} from "../../../data/label_registry"; import { findRelated } from "../../../data/search"; import { showAlertDialog, @@ -77,12 +84,6 @@ import { documentationUrl } from "../../../util/documentation-url"; import { showAssignCategoryDialog } from "../category/show-dialog-assign-category"; import { configSections } from "../ha-panel-config"; import { showNewAutomationDialog } from "./show-dialog-new-automation"; -import "../../../components/data-table/ha-data-table-labels"; -import { - LabelRegistryEntry, - subscribeLabelRegistry, -} from "../../../data/label_registry"; -import "../../../components/ha-filter-labels"; type AutomationItem = AutomationEntity & { name: string; @@ -509,6 +510,13 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) { `; } + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if (changedProps.has("_entityReg")) { + this._applyFilters(); + } + } + firstUpdated() { if (this._searchParms.has("blueprint")) { this._filterBlueprint(); diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts index 2f02ae82a9..36826e56df 100644 --- a/src/panels/config/scene/ha-scene-dashboard.ts +++ b/src/panels/config/scene/ha-scene-dashboard.ts @@ -16,6 +16,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, + PropertyValues, TemplateResult, css, html, @@ -297,6 +298,13 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) { } ); + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if (changedProps.has("_entityReg")) { + this._applyFilters(); + } + } + protected hassSubscribe(): (UnsubscribeFunc | Promise)[] { return [ subscribeCategoryRegistry(this.hass.connection, "scene", (categories) => { diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index 4449f1e7fe..fa9a4b9208 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -15,6 +15,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, + PropertyValues, TemplateResult, css, html, @@ -560,6 +561,13 @@ class HaScriptPicker extends SubscribeMixin(LitElement) { this._filteredScripts = items ? [...items] : undefined; } + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if (changedProps.has("_entityReg")) { + this._applyFilters(); + } + } + firstUpdated() { if (this._searchParms.has("blueprint")) { this._filterBlueprint(); From e5c43fcfcd9e8260717364732ed7c9ff5162efa6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 12:44:45 +0100 Subject: [PATCH 07/18] Update typescript-eslint monorepo to v7.4.0 (#20256) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 +- yarn.lock | 104 +++++++++++++++++++++++++-------------------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/package.json b/package.json index 0dd3d2590e..cece79f41b 100644 --- a/package.json +++ b/package.json @@ -185,8 +185,8 @@ "@types/tar": "6.1.11", "@types/ua-parser-js": "0.7.39", "@types/webspeechapi": "0.0.29", - "@typescript-eslint/eslint-plugin": "7.3.1", - "@typescript-eslint/parser": "7.3.1", + "@typescript-eslint/eslint-plugin": "7.4.0", + "@typescript-eslint/parser": "7.4.0", "@web/dev-server": "0.1.38", "@web/dev-server-rollup": "0.4.1", "babel-loader": "9.1.3", diff --git a/yarn.lock b/yarn.lock index 14b0b29805..93b495eaf2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4543,15 +4543,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/eslint-plugin@npm:7.3.1" +"@typescript-eslint/eslint-plugin@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.4.0" dependencies: "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:7.3.1" - "@typescript-eslint/type-utils": "npm:7.3.1" - "@typescript-eslint/utils": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" + "@typescript-eslint/scope-manager": "npm:7.4.0" + "@typescript-eslint/type-utils": "npm:7.4.0" + "@typescript-eslint/utils": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.2.4" @@ -4564,44 +4564,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/8ed276113a714d93ab3ababb1179e4785bd9378e6d97726519ea1d2ac502a94475e0be988c2ec427dcfc1e6950329d58da6e64131ee87028fce63493461cc51a + checksum: 10/9bd8852c7e4e9608c3fded94f7c60506cc7d2b6d8a8c1cad6d48969a7363751b20282874e55ccdf180635cf204cb10b3e1e5c3d1cff34d4fcd07762be3fc138e languageName: node linkType: hard -"@typescript-eslint/parser@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/parser@npm:7.3.1" +"@typescript-eslint/parser@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/parser@npm:7.4.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.3.1" - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/typescript-estree": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" + "@typescript-eslint/scope-manager": "npm:7.4.0" + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/typescript-estree": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/018326010fec1dcefd75809ccac5102a475bf1e052d824b898d707e7c0bf3e51e101164b410d1b2a513628985c96eb412538644d2005e26b99a22db6eb9402df + checksum: 10/142a9e1187d305ed43b4fef659c36fa4e28359467198c986f0955c70b4067c9799f4c85d9881fbf099c55dfb265e30666e28b3ef290520e242b45ca7cb8e4ca9 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/scope-manager@npm:7.3.1" +"@typescript-eslint/scope-manager@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/scope-manager@npm:7.4.0" dependencies: - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" - checksum: 10/7384d1f46d7f3678a1135a1ac0bd8b6dfa2f01e93b19e2510c7082766cf6983a1bf80b4ccf498651199a81d9f2bdb65101fd7a19226a723260514204d0c30b34 + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" + checksum: 10/8cf9292444f9731017a707cac34bef5ae0eb33b5cd42ed07fcd046e981d97889d9201d48e02f470f2315123f53771435e10b1dc81642af28a11df5352a8e8be2 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/type-utils@npm:7.3.1" +"@typescript-eslint/type-utils@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/type-utils@npm:7.4.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.3.1" - "@typescript-eslint/utils": "npm:7.3.1" + "@typescript-eslint/typescript-estree": "npm:7.4.0" + "@typescript-eslint/utils": "npm:7.4.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.0.1" peerDependencies: @@ -4609,23 +4609,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/fae9003a76a8f2a2a4bb88dc0f82c0a1ca0688633183fac391920e7124a12807aac84bb287a21f61e99523c15223d1c08e7680685ebf21d07429604cba6c420b + checksum: 10/a8bd0929d8237679b2b8a7817f070a4b9658ee976882fba8ff37e4a70dd33f87793e1b157771104111fe8054eaa8ad437a010b6aa465072fbdb932647125db2d languageName: node linkType: hard -"@typescript-eslint/types@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/types@npm:7.3.1" - checksum: 10/c9c8eae1cf937cececd99a253bd65eb71b40206e79cf917ad9c3b3ab80cc7ce5fefb2804f9fd2a70e7438951f0d1e63df3031fc61e3a08dfef5fde208a12e0ed +"@typescript-eslint/types@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/types@npm:7.4.0" + checksum: 10/2782c5bf65cd3dfa9cd32bc3023676bbca22144987c3f6c6b67fd96c73d4a60b85a57458c49fd11b9971ac6531824bb3ae0664491e7a6de25d80c523c9be92b7 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/typescript-estree@npm:7.3.1" +"@typescript-eslint/typescript-estree@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.4.0" dependencies: - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/visitor-keys": "npm:7.4.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -4635,34 +4635,34 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/363ad9864b56394b4000dff7c2b77d0ea52042c3c20e3b86c0f3c66044915632d9890255527c6f3a5ef056886dec72e38fbcfce49d4ad092c160440f54128230 + checksum: 10/162ec9d7582f45588342e1be36fdb60e41f50bbdfbc3035c91b517ff5d45244f776921c88d88e543e1c7d0f1e6ada5474a8316b78f1b0e6d2233b101bc45b166 languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/utils@npm:7.3.1" +"@typescript-eslint/utils@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/utils@npm:7.4.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.12" "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:7.3.1" - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/typescript-estree": "npm:7.3.1" + "@typescript-eslint/scope-manager": "npm:7.4.0" + "@typescript-eslint/types": "npm:7.4.0" + "@typescript-eslint/typescript-estree": "npm:7.4.0" semver: "npm:^7.5.4" peerDependencies: eslint: ^8.56.0 - checksum: 10/234d9d65fe5d0f4a31345bd8f5a6f2879a578b3a531a14c2b3edaa7fb587c71d26249f86c41857382c0405384dc104955c02b588b3cee6fc2734f1ae40aef07b + checksum: 10/ffed27e770c486cd000ff892d9049b0afe8b9d6318452a5355b78a37436cbb414bceacae413a2ac813f3e584684825d5e0baa2e6376b7ad6013a108ac91bc19d languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/visitor-keys@npm:7.3.1" +"@typescript-eslint/visitor-keys@npm:7.4.0": + version: 7.4.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.4.0" dependencies: - "@typescript-eslint/types": "npm:7.3.1" + "@typescript-eslint/types": "npm:7.4.0" eslint-visitor-keys: "npm:^3.4.1" - checksum: 10/163a93597c1d696920a19b3c1627d02368bdd52059f811c0fadd680c38034bb6418ebefe99d8ce26e0dd44ae184f18fab186af775de1a8771256be1a7905c174 + checksum: 10/70dc99f2ad116c6e2d9e55af249e4453e06bba2ceea515adef2d2e86e97e557865bb1b1d467667462443eb0d624baba36f7442fd1082f3874339bbc381c26e93 languageName: node linkType: hard @@ -9688,8 +9688,8 @@ __metadata: "@types/tar": "npm:6.1.11" "@types/ua-parser-js": "npm:0.7.39" "@types/webspeechapi": "npm:0.0.29" - "@typescript-eslint/eslint-plugin": "npm:7.3.1" - "@typescript-eslint/parser": "npm:7.3.1" + "@typescript-eslint/eslint-plugin": "npm:7.4.0" + "@typescript-eslint/parser": "npm:7.4.0" "@vaadin/combo-box": "npm:24.3.10" "@vaadin/vaadin-themable-mixin": "npm:24.3.10" "@vibrant/color": "npm:3.2.1-alpha.1" From 11cf2ec39d1f76250202865414bba5e272b3ec6b Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 15:41:05 +0100 Subject: [PATCH 08/18] Fix selecting no category message (#20268) --- src/panels/config/category/ha-category-picker.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/panels/config/category/ha-category-picker.ts b/src/panels/config/category/ha-category-picker.ts index 16b15fe794..3cd495935a 100644 --- a/src/panels/config/category/ha-category-picker.ts +++ b/src/panels/config/category/ha-category-picker.ts @@ -226,6 +226,8 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) { if (newValue === NO_CATEGORIES_ID) { newValue = ""; + this.comboBox.setInputValue(""); + return; } if (![ADD_NEW_SUGGESTION_ID, ADD_NEW_ID].includes(newValue)) { From e05595f318efcedbba930744bfcc3e808c4ce145 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 16:09:10 +0100 Subject: [PATCH 09/18] Fix add category and add label animation (#20272) --- src/components/ha-filter-categories.ts | 13 ++++++++++++- src/components/ha-filter-labels.ts | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/ha-filter-categories.ts b/src/components/ha-filter-categories.ts index 0555d06388..015f572b21 100644 --- a/src/components/ha-filter-categories.ts +++ b/src/components/ha-filter-categories.ts @@ -144,7 +144,11 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) { : nothing} ${this.expanded - ? html` + ? html` ${this.hass.localize("ui.panel.config.category.editor.add")} ` @@ -256,6 +260,7 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) { css` :host { border-bottom: 1px solid var(--divider-color); + position: relative; } :host([expanded]) { flex: 1; @@ -293,6 +298,12 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) { .warning { color: var(--error-color); } + .add { + position: absolute; + bottom: 0; + right: 0; + left: 0; + } `, ]; } diff --git a/src/components/ha-filter-labels.ts b/src/components/ha-filter-labels.ts index 3213f22a6f..8ba3acd20a 100644 --- a/src/components/ha-filter-labels.ts +++ b/src/components/ha-filter-labels.ts @@ -88,7 +88,11 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) { : nothing} ${this.expanded - ? html` + ? html` ${this.hass.localize("ui.panel.config.labels.add_label")} ` @@ -149,6 +153,7 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) { haStyleScrollbar, css` :host { + position: relative; border-bottom: 1px solid var(--divider-color); } :host([expanded]) { @@ -186,6 +191,12 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) { --ha-label-background-color: var(--color, var(--grey-color)); --ha-label-background-opacity: 0.5; } + .add { + position: absolute; + bottom: 0; + right: 0; + left: 0; + } `, ]; } From 8368f977b960761138d29c30da914ec9326c20c1 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 16:10:41 +0100 Subject: [PATCH 10/18] Improve data table search bar style (#20271) --- src/components/ha-outlined-text-field.ts | 38 +++++++++++++++++++++ src/components/search-input-outlined.ts | 42 ++++++++---------------- src/resources/ha-style.ts | 1 + src/resources/styles-data.ts | 1 + 4 files changed, 53 insertions(+), 29 deletions(-) create mode 100644 src/components/ha-outlined-text-field.ts diff --git a/src/components/ha-outlined-text-field.ts b/src/components/ha-outlined-text-field.ts new file mode 100644 index 0000000000..0580f65fcb --- /dev/null +++ b/src/components/ha-outlined-text-field.ts @@ -0,0 +1,38 @@ +import { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field"; +import "element-internals-polyfill"; +import { css } from "lit"; +import { customElement } from "lit/decorators"; + +@customElement("ha-outlined-text-field") +export class HaOutlinedTextField extends MdOutlinedTextField { + static override styles = [ + ...super.styles, + css` + :host { + --md-sys-color-on-surface: var(--primary-text-color); + --md-sys-color-primary: var(--primary-text-color); + --md-outlined-text-field-input-text-color: var(--primary-text-color); + --md-sys-color-on-surface-variant: var(--secondary-text-color); + --md-outlined-field-outline-color: var(--outline-color); + --md-outlined-field-focus-outline-color: var(--primary-color); + --md-outlined-field-hover-outline-color: var(--outline-hover-color); + } + :host([dense]) { + --md-outlined-field-top-space: 5.5px; + --md-outlined-field-bottom-space: 5.5px; + --md-outlined-field-container-shape-start-start: 10px; + --md-outlined-field-container-shape-start-end: 10px; + --md-outlined-field-container-shape-end-end: 10px; + --md-outlined-field-container-shape-end-start: 10px; + --md-outlined-field-focus-outline-width: 1px; + --mdc-icon-size: var(--md-input-chip-icon-size, 18px); + } + `, + ]; +} + +declare global { + interface HTMLElementTagNameMap { + "ha-outlined-text-field": HaOutlinedTextField; + } +} diff --git a/src/components/search-input-outlined.ts b/src/components/search-input-outlined.ts index 06b74dffc1..f949323cac 100644 --- a/src/components/search-input-outlined.ts +++ b/src/components/search-input-outlined.ts @@ -1,11 +1,11 @@ -import "@material/web/textfield/outlined-text-field"; -import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field"; import { mdiMagnify } from "@mdi/js"; import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit"; import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { HomeAssistant } from "../types"; import "./ha-icon-button"; +import "./ha-outlined-text-field"; +import type { HaOutlinedTextField } from "./ha-outlined-text-field"; import "./ha-svg-icon"; @customElement("search-input-outlined") @@ -30,19 +30,22 @@ class SearchInputOutlined extends LitElement { this._input?.focus(); } - @query("md-outlined-text-field", true) private _input!: MdOutlinedTextField; + @query("ha-outlined-text-field", true) private _input!: HaOutlinedTextField; protected render(): TemplateResult { + const placeholder = + this.placeholder || this.hass.localize("ui.common.search"); + return html` - - + `; } @@ -67,40 +70,21 @@ class SearchInputOutlined extends LitElement { return css` :host { display: inline-flex; + /* For iOS */ + z-index: 0; } - md-outlined-text-field { + ha-outlined-text-field { display: block; width: 100%; - --md-sys-color-on-surface: var(--primary-text-color); - --md-sys-color-primary: var(--primary-text-color); - --md-outlined-text-field-input-text-color: var(--primary-text-color); - --md-sys-color-on-surface-variant: var(--secondary-text-color); - --md-outlined-field-top-space: 5.5px; - --md-outlined-field-bottom-space: 5.5px; - --md-outlined-field-outline-color: var(--outline-color); - --md-outlined-field-container-shape-start-start: 10px; - --md-outlined-field-container-shape-start-end: 10px; - --md-outlined-field-container-shape-end-end: 10px; - --md-outlined-field-container-shape-end-start: 10px; - --md-outlined-field-focus-outline-width: 1px; - --md-outlined-field-focus-outline-color: var(--primary-color); } ha-svg-icon, ha-icon-button { display: flex; - --mdc-icon-size: var(--md-input-chip-icon-size, 18px); color: var(--primary-text-color); } ha-svg-icon { outline: none; } - .clear-button { - --mdc-icon-size: 20px; - } - .trailing { - display: flex; - align-items: center; - } `; } } diff --git a/src/resources/ha-style.ts b/src/resources/ha-style.ts index e06a943982..664b2c2cf7 100644 --- a/src/resources/ha-style.ts +++ b/src/resources/ha-style.ts @@ -32,6 +32,7 @@ const mainStyles = css` --accent-color: ${unsafeCSS(DEFAULT_ACCENT_COLOR)}; --divider-color: rgba(0, 0, 0, 0.12); --outline-color: rgba(0, 0, 0, 0.12); + --outline-hover-color: rgba(0, 0, 0, 0.24); --scrollbar-thumb-color: rgb(194, 194, 194); diff --git a/src/resources/styles-data.ts b/src/resources/styles-data.ts index 87114d6885..8670024ca6 100644 --- a/src/resources/styles-data.ts +++ b/src/resources/styles-data.ts @@ -15,6 +15,7 @@ export const darkStyles = { "switch-unchecked-track-color": "#9b9b9b", "divider-color": "rgba(225, 225, 225, .12)", "outline-color": "rgba(225, 225, 225, .12)", + "outline-hover-color": "rgba(225, 225, 225, .24)", "mdc-ripple-color": "#AAAAAA", "mdc-linear-progress-buffer-color": "rgba(255, 255, 255, 0.1)", From cb1c2b59df14909a5054a97a37c060bc22708012 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 16:12:18 +0100 Subject: [PATCH 11/18] Use primary color for filter badge color (#20263) --- src/components/ha-filter-blueprints.ts | 4 ++-- src/components/ha-filter-categories.ts | 4 ++-- src/components/ha-filter-devices.ts | 4 ++-- src/components/ha-filter-entities.ts | 4 ++-- src/components/ha-filter-floor-areas.ts | 4 ++-- src/components/ha-filter-integrations.ts | 4 ++-- src/components/ha-filter-labels.ts | 4 ++-- src/components/ha-filter-states.ts | 4 ++-- src/layouts/hass-tabs-subpage-data-table.ts | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/ha-filter-blueprints.ts b/src/components/ha-filter-blueprints.ts index ac11837c09..f7ef069c5e 100644 --- a/src/components/ha-filter-blueprints.ts +++ b/src/components/ha-filter-blueprints.ts @@ -157,11 +157,11 @@ export class HaFilterBlueprints extends LitElement { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } `, ]; diff --git a/src/components/ha-filter-categories.ts b/src/components/ha-filter-categories.ts index 015f572b21..fdaa8d481a 100644 --- a/src/components/ha-filter-categories.ts +++ b/src/components/ha-filter-categories.ts @@ -284,11 +284,11 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } mwc-list { --mdc-list-item-meta-size: auto; diff --git a/src/components/ha-filter-devices.ts b/src/components/ha-filter-devices.ts index 72692f3cfd..944b26c87c 100644 --- a/src/components/ha-filter-devices.ts +++ b/src/components/ha-filter-devices.ts @@ -185,11 +185,11 @@ export class HaFilterDevices extends LitElement { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } ha-check-list-item { width: 100%; diff --git a/src/components/ha-filter-entities.ts b/src/components/ha-filter-entities.ts index c2948451d9..5d43de5f1c 100644 --- a/src/components/ha-filter-entities.ts +++ b/src/components/ha-filter-entities.ts @@ -199,11 +199,11 @@ export class HaFilterEntities extends LitElement { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } ha-check-list-item { --mdc-list-item-graphic-margin: 16px; diff --git a/src/components/ha-filter-floor-areas.ts b/src/components/ha-filter-floor-areas.ts index 2ee817c370..6960621fb3 100644 --- a/src/components/ha-filter-floor-areas.ts +++ b/src/components/ha-filter-floor-areas.ts @@ -267,11 +267,11 @@ export class HaFilterFloorAreas extends SubscribeMixin(LitElement) { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } ha-check-list-item { --mdc-list-item-graphic-margin: 16px; diff --git a/src/components/ha-filter-integrations.ts b/src/components/ha-filter-integrations.ts index 7373c6af3a..6fd909168c 100644 --- a/src/components/ha-filter-integrations.ts +++ b/src/components/ha-filter-integrations.ts @@ -165,11 +165,11 @@ export class HaFilterIntegrations extends LitElement { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } `, ]; diff --git a/src/components/ha-filter-labels.ts b/src/components/ha-filter-labels.ts index 8ba3acd20a..dd7ceada0b 100644 --- a/src/components/ha-filter-labels.ts +++ b/src/components/ha-filter-labels.ts @@ -178,11 +178,11 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } .warning { color: var(--error-color); diff --git a/src/components/ha-filter-states.ts b/src/components/ha-filter-states.ts index 83a2da46eb..71451460b0 100644 --- a/src/components/ha-filter-states.ts +++ b/src/components/ha-filter-states.ts @@ -147,11 +147,11 @@ export class HaFilterStates extends LitElement { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } `, ]; diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts index 772f1a169c..61bff9c04f 100644 --- a/src/layouts/hass-tabs-subpage-data-table.ts +++ b/src/layouts/hass-tabs-subpage-data-table.ts @@ -611,11 +611,11 @@ export class HaTabsSubpageDataTable extends LitElement { border-radius: 50%; font-weight: 400; font-size: 11px; - background-color: var(--accent-color); + background-color: var(--primary-color); line-height: 16px; text-align: center; padding: 0px 2px; - color: var(--text-accent-color, var(--text-primary-color)); + color: var(--text-primary-color); } .narrow-header-row { From 99695d6cb3f72c45d36742722faf3773c08d0037 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 16:15:21 +0100 Subject: [PATCH 12/18] Use md-menu for group by and sort by for data table (#20266) --- src/layouts/hass-tabs-subpage-data-table.ts | 149 +++++++++++++------- 1 file changed, 96 insertions(+), 53 deletions(-) diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts index 61bff9c04f..b4d4ddc58f 100644 --- a/src/layouts/hass-tabs-subpage-data-table.ts +++ b/src/layouts/hass-tabs-subpage-data-table.ts @@ -1,6 +1,9 @@ import { ResizeController } from "@lit-labs/observers/resize-controller"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@material/mwc-button/mwc-button"; +import "@material/web/menu/menu"; +import type { MdMenu } from "@material/web/menu/menu"; +import "@material/web/menu/menu-item"; import { mdiArrowDown, mdiArrowUp, @@ -19,6 +22,7 @@ import { nothing, } from "lit"; import { customElement, property, query, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../common/dom/fire_event"; import { LocalizeFunc } from "../common/translations/localize"; import "../components/chips/ha-assist-chip"; @@ -173,6 +177,10 @@ export class HaTabsSubpageDataTable extends LitElement { @query("ha-data-table", true) private _dataTable!: HaDataTable; + @query("#group-by-menu") private _groupByMenu!: MdMenu; + + @query("#sort-by-menu") private _sortByMenu!: MdMenu; + private _showPaneController = new ResizeController(this, { callback: (entries) => entries[0]?.contentRect.width > 750, }); @@ -187,6 +195,14 @@ export class HaTabsSubpageDataTable extends LitElement { } } + private _toggleGroupBy() { + this._groupByMenu.open = !this._groupByMenu.open; + } + + private _toggleSortBy() { + this._sortByMenu.open = !this._sortByMenu.open; + } + protected render(): TemplateResult { const localize = this.localizeFunc || this.hass.localize; const showPane = this._showPaneController.value ?? !this.narrow; @@ -226,73 +242,35 @@ export class HaTabsSubpageDataTable extends LitElement { `; const sortByMenu = Object.values(this.columns).find((col) => col.sortable) - ? html` + ? html` - ${Object.entries(this.columns).map(([id, column]) => - column.sortable - ? html` - ${this._sortColumn === id - ? html`` - : nothing} - ${column.title || column.label} - ` - : nothing - )} - ` + ` : nothing; const groupByMenu = Object.values(this.columns).find((col) => col.groupable) - ? html` + ? html` - ${Object.entries(this.columns).map(([id, column]) => - column.groupable - ? html` - ${column.title || column.label} - ` - : nothing - )} -
  • - ${localize( - "ui.components.subpage-data-table.dont_group_by" - )} -
    ` + ` : nothing; return html` @@ -431,6 +409,58 @@ export class HaTabsSubpageDataTable extends LitElement { `}
    + + ${Object.entries(this.columns).map(([id, column]) => + column.groupable + ? html` + + ${column.title || column.label} + + ` + : nothing + )} +
  • + ${localize( + "ui.components.subpage-data-table.dont_group_by" + )} +
    + + ${Object.entries(this.columns).map(([id, column]) => + column.sortable + ? html` + + ${this._sortColumn === id + ? html` + + ` + : nothing} + ${column.title || column.label} + + ` + : nothing + )} + `; } @@ -449,6 +479,7 @@ export class HaTabsSubpageDataTable extends LitElement { private _handleSortBy(ev) { ev.stopPropagation(); + ev.preventDefault(); const columnId = ev.currentTarget.value; if (!this._sortDirection || this._sortColumn !== columnId) { this._sortDirection = "asc"; @@ -656,13 +687,6 @@ export class HaTabsSubpageDataTable extends LitElement { ha-assist-chip { --ha-assist-chip-container-shape: 10px; } - ha-button-menu { - --mdc-list-item-meta-size: 16px; - --mdc-list-item-meta-display: flex; - } - ha-button-menu ha-assist-chip { - --md-assist-chip-trailing-space: 8px; - } .select-mode-chip { --md-assist-chip-icon-label-space: 0; @@ -688,6 +712,25 @@ export class HaTabsSubpageDataTable extends LitElement { display: flex; flex-direction: column; } + /* TODO: Migrate to ha-menu and ha-menu-item */ + md-menu { + --md-menu-container-color: var(--card-background-color); + } + md-menu-item { + --md-menu-item-label-text-color: var(--primary-text-color); + --mdc-icon-size: 16px; + --md-menu-item-selected-container-color: rgba( + var(--rgb-primary-color), + 0.15 + ); + } + md-menu-item.selected { + --md-menu-item-label-text-color: var(--primary-color); + } + #sort-by-anchor, + #group-by-anchor { + --md-assist-chip-trailing-space: 8px; + } `; } } From abd02eda0f01d814fcc89b78be1ca0c8f007a8e9 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 16:16:01 +0100 Subject: [PATCH 13/18] Fix empty line in data table when using group_by (#20273) --- src/components/data-table/ha-data-table.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index 06d515a115..cf442f525f 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -512,10 +512,6 @@ export class HaDataTable extends LitElement { items.push({ append: true, content: this.appendRow }); } - if (this.hasFab) { - items.push({ empty: true }); - } - if (this.groupColumn) { const grouped = groupBy(items, (item) => item[this.groupColumn!]); if (grouped.undefined) { @@ -555,6 +551,10 @@ export class HaDataTable extends LitElement { } else { this._items = items; } + + if (this.hasFab) { + this._items = [...this._items, { empty: true }]; + } } else { this._items = data; } From f539516252d8bad09a6529dec27a016bc0f82798 Mon Sep 17 00:00:00 2001 From: Simon Lamon <32477463+silamon@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:41:18 +0100 Subject: [PATCH 14/18] Label filters for devices & entities (#20253) More label filters --- .../devices/ha-config-devices-dashboard.ts | 32 +++++++++++++------ .../config/entities/ha-config-entities.ts | 32 +++++++++++++------ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index 0194fd079c..b8f90a987a 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -32,6 +32,7 @@ import "../../../components/ha-filter-devices"; import "../../../components/ha-filter-floor-areas"; import "../../../components/ha-filter-integrations"; import "../../../components/ha-filter-states"; +import "../../../components/ha-filter-labels"; import "../../../components/ha-icon-button"; import "../../../components/ha-alert"; import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries"; @@ -221,16 +222,16 @@ export class HaConfigDeviceDashboard extends LitElement { const filteredDomains = new Set(); - Object.entries(filters).forEach(([key, flter]) => { - if (key === "config_entry" && flter.value?.length) { + Object.entries(filters).forEach(([key, filter]) => { + if (key === "config_entry" && filter.value?.length) { outputDevices = outputDevices.filter((device) => device.config_entries.some((entryId) => - flter.value?.includes(entryId) + filter.value?.includes(entryId) ) ); const configEntries = entries.filter( - (entry) => entry.entry_id && flter.value?.includes(entry.entry_id) + (entry) => entry.entry_id && filter.value?.includes(entry.entry_id) ); configEntries.forEach((configEntry) => { @@ -239,17 +240,21 @@ export class HaConfigDeviceDashboard extends LitElement { if (configEntries.length === 1) { filteredConfigEntry = configEntries[0]; } - } else if (key === "ha-filter-integrations" && flter.value?.length) { + } else if (key === "ha-filter-integrations" && filter.value?.length) { const entryIds = entries - .filter((entry) => flter.value!.includes(entry.domain)) + .filter((entry) => filter.value!.includes(entry.domain)) .map((entry) => entry.entry_id); outputDevices = outputDevices.filter((device) => device.config_entries.some((entryId) => entryIds.includes(entryId)) ); - flter.value!.forEach((domain) => filteredDomains.add(domain)); - } else if (flter.items) { + filter.value!.forEach((domain) => filteredDomains.add(domain)); + } else if (key === "ha-filter-labels" && filter.value?.length) { outputDevices = outputDevices.filter((device) => - flter.items!.has(device.id) + device.labels.some((lbl) => filter.value!.includes(lbl)) + ); + } else if (filter.items) { + outputDevices = outputDevices.filter((device) => + filter.items!.has(device.id) ); } }); @@ -531,6 +536,15 @@ export class HaConfigDeviceDashboard extends LitElement { .narrow=${this.narrow} @expanded-changed=${this._filterExpanded} > + `; } diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index 8e6bc34bd5..ec5c63eafc 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -43,6 +43,7 @@ import "../../../components/ha-filter-devices"; import "../../../components/ha-filter-floor-areas"; import "../../../components/ha-filter-integrations"; import "../../../components/ha-filter-states"; +import "../../../components/ha-filter-labels"; import "../../../components/ha-icon"; import "../../../components/ha-icon-button"; import "../../../components/ha-svg-icon"; @@ -337,12 +338,12 @@ export class HaConfigEntities extends LitElement { let filteredConfigEntry: ConfigEntry | undefined; const filteredDomains = new Set(); - Object.entries(filters).forEach(([key, flter]) => { - if (key === "config_entry" && flter.value?.length) { + Object.entries(filters).forEach(([key, filter]) => { + if (key === "config_entry" && filter.value?.length) { filteredEntities = filteredEntities.filter( (entity) => entity.config_entry_id && - flter.value?.includes(entity.config_entry_id) + filter.value?.includes(entity.config_entry_id) ); if (!entries) { @@ -351,7 +352,7 @@ export class HaConfigEntities extends LitElement { } const configEntries = entries.filter( - (entry) => entry.entry_id && flter.value?.includes(entry.entry_id) + (entry) => entry.entry_id && filter.value?.includes(entry.entry_id) ); configEntries.forEach((configEntry) => { @@ -360,23 +361,27 @@ export class HaConfigEntities extends LitElement { if (configEntries.length === 1) { filteredConfigEntry = configEntries[0]; } - } else if (key === "ha-filter-integrations" && flter.value?.length) { + } else if (key === "ha-filter-integrations" && filter.value?.length) { if (!entries) { this._loadConfigEntries(); return; } const entryIds = entries - .filter((entry) => flter.value!.includes(entry.domain)) + .filter((entry) => filter.value!.includes(entry.domain)) .map((entry) => entry.entry_id); filteredEntities = filteredEntities.filter( (entity) => entity.config_entry_id && entryIds.includes(entity.config_entry_id) ); - flter.value!.forEach((domain) => filteredDomains.add(domain)); - } else if (flter.items) { + filter.value!.forEach((domain) => filteredDomains.add(domain)); + } else if (key === "ha-filter-labels" && filter.value?.length) { filteredEntities = filteredEntities.filter((entity) => - flter.items!.has(entity.entity_id) + entity.labels.some((lbl) => filter.value!.includes(lbl)) + ); + } else if (filter.items) { + filteredEntities = filteredEntities.filter((entity) => + filter.items!.has(entity.entity_id) ); } }); @@ -633,6 +638,15 @@ export class HaConfigEntities extends LitElement { .narrow=${this.narrow} @expanded-changed=${this._filterExpanded} > + ${includeAddDeviceFab ? html` Date: Fri, 29 Mar 2024 18:05:06 +0100 Subject: [PATCH 15/18] Fix floor creation in floor picker (#20276) --- src/components/ha-floor-picker.ts | 80 +++++++++++++++++-------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/src/components/ha-floor-picker.ts b/src/components/ha-floor-picker.ts index 1c6be3bf28..59886ffa29 100644 --- a/src/components/ha-floor-picker.ts +++ b/src/components/ha-floor-picker.ts @@ -38,10 +38,14 @@ import "./ha-list-item"; type ScorableFloorRegistryEntry = ScorableTextItem & FloorRegistryEntry; +const ADD_NEW_ID = "___ADD_NEW___"; +const NO_FLOORS_ID = "___NO_FLOORS___"; +const ADD_NEW_SUGGESTION_ID = "___ADD_NEW_SUGGESTION___"; + const rowRenderer: ComboBoxLitRenderer = (item) => html` ${item.name} @@ -146,18 +150,6 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) { noAdd: this["noAdd"], excludeFloors: this["excludeFloors"] ): FloorRegistryEntry[] => { - if (!floors.length) { - return [ - { - floor_id: "no_floors", - name: this.hass.localize("ui.components.floor-picker.no_floors"), - icon: null, - level: 0, - aliases: [], - }, - ]; - } - let deviceEntityLookup: DeviceEntityDisplayLookup = {}; let inputDevices: DeviceRegistryEntry[] | undefined; let inputEntities: EntityRegistryDisplayEntry[] | undefined; @@ -297,10 +289,10 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) { if (!outputFloors.length) { outputFloors = [ { - floor_id: "no_floors", - name: this.hass.localize("ui.components.floor-picker.no_match"), + floor_id: NO_FLOORS_ID, + name: this.hass.localize("ui.components.floor-picker.no_floors"), icon: null, - level: 0, + level: null, aliases: [], }, ]; @@ -311,10 +303,10 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) { : [ ...outputFloors, { - floor_id: "add_new", + floor_id: ADD_NEW_ID, name: this.hass.localize("ui.components.floor-picker.add_new"), icon: "mdi:plus", - level: 0, + level: null, aliases: [], }, ]; @@ -341,7 +333,7 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) { this.excludeFloors ).map((floor) => ({ ...floor, - strings: [floor.floor_id, floor.name], // ...floor.aliases + strings: [floor.floor_id, floor.name, ...floor.aliases], })); this.comboBox.items = floors; this.comboBox.filteredItems = floors; @@ -385,20 +377,36 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) { const filteredItems = fuzzyFilterSort( filterString, - target.items || [] + target.items?.filter( + (item) => ![NO_FLOORS_ID, ADD_NEW_ID].includes(item.label_id) + ) || [] ); - if (!this.noAdd && filteredItems?.length === 0) { - this._suggestion = filterString; - this.comboBox.filteredItems = [ - { - floor_id: "add_new_suggestion", - name: this.hass.localize( - "ui.components.floor-picker.add_new_sugestion", - { name: this._suggestion } - ), - picture: null, - }, - ]; + if (filteredItems.length === 0) { + if (this.noAdd) { + this.comboBox.filteredItems = [ + { + floor_id: NO_FLOORS_ID, + name: this.hass.localize("ui.components.floor-picker.no_floors"), + icon: null, + level: null, + aliases: [], + }, + ] as FloorRegistryEntry[]; + } else { + this._suggestion = filterString; + this.comboBox.filteredItems = [ + { + floor_id: ADD_NEW_SUGGESTION_ID, + name: this.hass.localize( + "ui.components.floor-picker.add_new_sugestion", + { name: this._suggestion } + ), + icon: "mdi:plus", + level: null, + aliases: [], + }, + ] as FloorRegistryEntry[]; + } } else { this.comboBox.filteredItems = filteredItems; } @@ -416,11 +424,13 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) { ev.stopPropagation(); let newValue = ev.detail.value; - if (newValue === "no_floors") { + if (newValue === NO_FLOORS_ID) { newValue = ""; + this.comboBox.setInputValue(""); + return; } - if (!["add_new_suggestion", "add_new"].includes(newValue)) { + if (![ADD_NEW_SUGGESTION_ID, ADD_NEW_ID].includes(newValue)) { if (newValue !== this._value) { this._setValue(newValue); } @@ -438,7 +448,7 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) { "ui.components.floor-picker.add_dialog.name" ), defaultValue: - newValue === "add_new_suggestion" ? this._suggestion : undefined, + newValue === ADD_NEW_SUGGESTION_ID ? this._suggestion : undefined, confirm: async (name) => { if (!name) { return; From 3a6382df55d2072c741394397e24306ded703969 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 18:46:34 +0100 Subject: [PATCH 16/18] Add labels on devices datatable (#20275) --- .../devices/ha-config-devices-dashboard.ts | 85 +++++++++++++++++-- 1 file changed, 76 insertions(+), 9 deletions(-) diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index b8f90a987a..ce3e0b26e7 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -10,6 +10,7 @@ import { nothing, } from "lit"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { HASSDomEvent } from "../../../common/dom/fire_event"; @@ -24,17 +25,18 @@ import { DataTableColumnContainer, RowClickedEvent, } from "../../../components/data-table/ha-data-table"; +import "../../../components/data-table/ha-data-table-labels"; import "../../../components/entity/ha-battery-icon"; +import "../../../components/ha-alert"; import "../../../components/ha-button-menu"; import "../../../components/ha-check-list-item"; import "../../../components/ha-fab"; import "../../../components/ha-filter-devices"; import "../../../components/ha-filter-floor-areas"; import "../../../components/ha-filter-integrations"; -import "../../../components/ha-filter-states"; import "../../../components/ha-filter-labels"; +import "../../../components/ha-filter-states"; import "../../../components/ha-icon-button"; -import "../../../components/ha-alert"; import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries"; import { fullEntitiesContext } from "../../../data/context"; import { @@ -48,7 +50,12 @@ import { findBatteryEntity, } from "../../../data/entity_registry"; import { IntegrationManifest } from "../../../data/integration"; +import { + LabelRegistryEntry, + subscribeLabelRegistry, +} from "../../../data/label_registry"; import "../../../layouts/hass-tabs-subpage-data-table"; +import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; import { brandsUrl } from "../../../util/brands-url"; @@ -61,10 +68,11 @@ interface DeviceRowData extends DeviceRegistryEntry { area?: string; integration?: string; battery_entity?: [string | undefined, string | undefined]; + label_entries: EntityRegistryEntry[]; } @customElement("ha-config-devices-dashboard") -export class HaConfigDeviceDashboard extends LitElement { +export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; @property({ type: Boolean }) public narrow = false; @@ -92,6 +100,9 @@ export class HaConfigDeviceDashboard extends LitElement { @state() private _expandedFilter?: string; + @state() + _labels!: LabelRegistryEntry[]; + private _ignoreLocationChange = false; public connectedCallback() { @@ -191,11 +202,17 @@ export class HaConfigDeviceDashboard extends LitElement { string, { value: string[] | undefined; items: Set | undefined } >, - localize: LocalizeFunc + localize: LocalizeFunc, + labelReg?: LabelRegistryEntry[] ) => { // Some older installations might have devices pointing at invalid entryIDs // So we guard for that. - let outputDevices: DeviceRowData[] = Object.values(devices); + let outputDevices: DeviceRowData[] = Object.values(devices).map( + (device) => ({ + ...device, + label_entries: [], + }) + ); const deviceEntityLookup: DeviceEntityLookup = {}; for (const entity of entities) { @@ -275,6 +292,12 @@ export class HaConfigDeviceDashboard extends LitElement { .map((entId) => entryLookup[entId]), manifestLookup ); + + const labels = labelReg && device?.labels; + const labelsEntries = (labels || []).map( + (lbl) => labelReg!.find((label) => label.label_id === lbl)! + ); + return { ...device, name: computeDeviceName( @@ -311,6 +334,7 @@ export class HaConfigDeviceDashboard extends LitElement { this.hass.states[ this._batteryEntity(device.id, deviceEntityLookup) || "" ]?.state, + label_entries: labelsEntries, }; }); @@ -356,8 +380,15 @@ export class HaConfigDeviceDashboard extends LitElement { direction: "asc", grows: true, template: (device) => html` - ${device.name} +
    ${device.name}
    ${device.area} | ${device.integration}
    + ${device.label_entries.length + ? html` + + ` + : nothing} `, }; } else { @@ -366,8 +397,18 @@ export class HaConfigDeviceDashboard extends LitElement { main: true, sortable: true, filterable: true, - grows: true, direction: "asc", + grows: true, + template: (device) => html` +
    ${device.name}
    + ${device.label_entries.length + ? html` + + ` + : nothing} + `, }; } @@ -446,9 +487,25 @@ export class HaConfigDeviceDashboard extends LitElement { ? this.hass.localize("ui.panel.config.devices.disabled") : "", }; + columns.labels = { + title: "", + hidden: true, + filterable: true, + template: (device) => + device.label_entries.map((lbl) => lbl.name).join(" "), + }; + return columns; }); + protected hassSubscribe(): (UnsubscribeFunc | Promise)[] { + return [ + subscribeLabelRegistry(this.hass.connection, (labels) => { + this._labels = labels; + }), + ]; + } + protected render(): TemplateResult { const { devicesOutput } = this._devicesAndFilterDomains( this.hass.devices, @@ -457,7 +514,8 @@ export class HaConfigDeviceDashboard extends LitElement { this.hass.areas, this.manifests, this._filters, - this.hass.localize + this.hass.localize, + this._labels ); return html` @@ -484,6 +542,7 @@ export class HaConfigDeviceDashboard extends LitElement { @row-click=${this._handleRowClicked} clickable hasFab + class=${this.narrow ? "narrow" : ""} > ).includes( @@ -625,6 +686,12 @@ export class HaConfigDeviceDashboard extends LitElement { static get styles(): CSSResultGroup { return [ css` + hass-tabs-subpage-data-table { + --data-table-row-height: 60px; + } + hass-tabs-subpage-data-table.narrow { + --data-table-row-height: 72px; + } ha-button-menu { margin-left: 8px; margin-inline-start: 8px; From f924f81ec1c65dc271907edb4a4d414664669d73 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 29 Mar 2024 18:47:22 +0100 Subject: [PATCH 17/18] Add labels on entities datatable (#20274) --- .../config/entities/ha-config-entities.ts | 74 +++++++++++++++---- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index ec5c63eafc..7df4b35bd8 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -10,7 +10,7 @@ import { mdiRestoreAlert, mdiUndo, } from "@mdi/js"; -import { HassEntity } from "home-assistant-js-websocket"; +import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, @@ -37,6 +37,8 @@ import type { RowClickedEvent, SelectionChangedEvent, } from "../../../components/data-table/ha-data-table"; +import "../../../components/data-table/ha-data-table-labels"; +import "../../../components/ha-alert"; import "../../../components/ha-button-menu"; import "../../../components/ha-check-list-item"; import "../../../components/ha-filter-devices"; @@ -47,7 +49,6 @@ import "../../../components/ha-filter-labels"; import "../../../components/ha-icon"; import "../../../components/ha-icon-button"; import "../../../components/ha-svg-icon"; -import "../../../components/ha-alert"; import { ConfigEntry, getConfigEntries } from "../../../data/config_entries"; import { fullEntitiesContext } from "../../../data/context"; import { UNAVAILABLE } from "../../../data/entity"; @@ -58,6 +59,10 @@ import { updateEntityRegistryEntry, } from "../../../data/entity_registry"; import { entryIcon } from "../../../data/icons"; +import { + LabelRegistryEntry, + subscribeLabelRegistry, +} from "../../../data/label_registry"; import { showAlertDialog, showConfirmationDialog, @@ -66,6 +71,7 @@ import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info import "../../../layouts/hass-loading-screen"; import "../../../layouts/hass-tabs-subpage-data-table"; import type { HaTabsSubpageDataTable } from "../../../layouts/hass-tabs-subpage-data-table"; +import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant, Route } from "../../../types"; import { configSections } from "../ha-panel-config"; @@ -87,10 +93,11 @@ export interface EntityRow extends StateEntity { status: string | undefined; area?: string; localized_platform: string; + label_entries: LabelRegistryEntry[]; } @customElement("ha-config-entities") -export class HaConfigEntities extends LitElement { +export class HaConfigEntities extends SubscribeMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; @property({ type: Boolean }) public isWide = false; @@ -120,6 +127,9 @@ export class HaConfigEntities extends LitElement { @state() private _expandedFilter?: string; + @state() + _labels!: LabelRegistryEntry[]; + @query("hass-tabs-subpage-data-table", true) private _dataTable!: HaTabsSubpageDataTable; @@ -203,14 +213,21 @@ export class HaConfigEntities extends LitElement { filterable: true, direction: "asc", grows: true, - template: narrow - ? (entry) => html` - ${entry.name}
    -
    + template: (entry) => html` +
    ${entry.name}
    + ${narrow + ? html`
    ${entry.entity_id} | ${entry.localized_platform} -
    - ` - : undefined, +
    ` + : nothing} + ${entry.label_entries.length + ? html` + + ` + : nothing} + `, }, entity_id: { title: localize("ui.panel.config.entities.picker.headers.entity_id"), @@ -302,6 +319,13 @@ export class HaConfigEntities extends LitElement { ` : "—", }, + labels: { + title: "", + hidden: true, + filterable: true, + template: (entry) => + entry.label_entries.map((lbl) => lbl.name).join(" "), + }, }) ); @@ -316,7 +340,8 @@ export class HaConfigEntities extends LitElement { string, { value: string[] | undefined; items: Set | undefined } >, - entries?: ConfigEntry[] + entries?: ConfigEntry[], + labelReg?: LabelRegistryEntry[] ) => { const result: EntityRow[] = []; @@ -409,6 +434,11 @@ export class HaConfigEntities extends LitElement { continue; } + const labels = labelReg && entry?.labels; + const labelsEntries = (labels || []).map( + (lbl) => labelReg!.find((label) => label.label_id === lbl)! + ); + result.push({ ...entry, entity, @@ -436,6 +466,7 @@ export class HaConfigEntities extends LitElement { : localize( "ui.panel.config.entities.picker.status.available" ), + label_entries: labelsEntries, }); } @@ -443,6 +474,14 @@ export class HaConfigEntities extends LitElement { } ); + protected hassSubscribe(): (UnsubscribeFunc | Promise)[] { + return [ + subscribeLabelRegistry(this.hass.connection, (labels) => { + this._labels = labels; + }), + ]; + } + protected render() { if (!this.hass || this._entities === undefined) { return html` `; @@ -456,7 +495,8 @@ export class HaConfigEntities extends LitElement { this.hass.areas, this._stateEntities, this._filters, - this._entries + this._entries, + this._labels ); const includeAddDeviceFab = @@ -497,6 +537,7 @@ export class HaConfigEntities extends LitElement { @row-click=${this._openEditEntry} id="entity_id" .hasFab=${includeAddDeviceFab} + class=${this.narrow ? "narrow" : ""} > Date: Fri, 29 Mar 2024 19:09:09 +0100 Subject: [PATCH 18/18] Bumped version to 20240329.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 608b3b0e16..0497dd5d5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240328.0" +version = "20240329.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md"