From de85b08de43b7421935e8d4e220311127e6d6762 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Thu, 22 Jan 2026 20:00:51 +0100 Subject: [PATCH] Migrate ha-md-button-menu to ha-dropdown in 6 files (#29137) Refactor dropdown menus to use ha-dropdown and ha-dropdown-item components - Replaced ha-md-button-menu and related components with ha-dropdown and ha-dropdown-item in dialog-edit-sidebar, hass-tabs-subpage-data-table, ha-config-devices-dashboard, ha-config-entities. - Updated event handling to accommodate new dropdown structure. - Added wa-divider for better visual separation in dropdowns. - Improved accessibility and usability of dropdown menus across various components. --- src/components/ha-icon-overflow-menu.ts | 34 +- .../controls/more-info-media_player.ts | 59 ++- src/dialogs/sidebar/dialog-edit-sidebar.ts | 21 +- src/layouts/hass-tabs-subpage-data-table.ts | 155 +++--- .../devices/ha-config-devices-dashboard.ts | 285 ++++++----- .../config/entities/ha-config-entities.ts | 459 +++++++++--------- 6 files changed, 529 insertions(+), 484 deletions(-) diff --git a/src/components/ha-icon-overflow-menu.ts b/src/components/ha-icon-overflow-menu.ts index 12a6701f31..1ffec8188d 100644 --- a/src/components/ha-icon-overflow-menu.ts +++ b/src/components/ha-icon-overflow-menu.ts @@ -1,16 +1,16 @@ +import "@home-assistant/webawesome/dist/components/divider/divider"; import { mdiDotsVertical } from "@mdi/js"; import type { TemplateResult } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; import { haStyle } from "../resources/styles"; import type { HomeAssistant } from "../types"; -import "./ha-md-button-menu"; +import "./ha-dropdown"; +import "./ha-dropdown-item"; import "./ha-icon-button"; +import "./ha-md-divider"; import "./ha-svg-icon"; import "./ha-tooltip"; -import "./ha-md-menu-item"; -import "./ha-md-divider"; export interface IconOverflowMenuItem { [key: string]: any; @@ -39,10 +39,7 @@ export class HaIconOverflowMenu extends LitElement { return html` ${this.narrow ? html` - + item.divider - ? html`` - : html`` + : html` - + ${item.label} - ` + ` )} - ` + ` : html` ${this.items.map((item) => diff --git a/src/dialogs/more-info/controls/more-info-media_player.ts b/src/dialogs/more-info/controls/more-info-media_player.ts index 85e5a79c4f..0e4256a4fd 100644 --- a/src/dialogs/more-info/controls/more-info-media_player.ts +++ b/src/dialogs/more-info/controls/more-info-media_player.ts @@ -24,11 +24,12 @@ import { import { VolumeSliderController } from "../../../common/util/volume-slider"; import "../../../components/chips/ha-assist-chip"; import "../../../components/ha-button"; +import "../../../components/ha-dropdown"; +import "../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../components/ha-dropdown-item"; import "../../../components/ha-icon-button"; import "../../../components/ha-list-item"; import "../../../components/ha-marquee-text"; -import "../../../components/ha-md-button-menu"; -import "../../../components/ha-md-menu-item"; import "../../../components/ha-select"; import type { HaSlider } from "../../../components/ha-slider"; import "../../../components/ha-svg-icon"; @@ -201,29 +202,30 @@ class MoreInfoMediaPlayer extends LitElement { return nothing; } - return html` + return html` ${this.stateObj.attributes.source_list!.map( (source) => - html` ${this.hass.formatEntityAttributeValue( this.stateObj!, "source", source )} - ` + ` )} - `; + `; } protected _renderSoundMode() { @@ -238,29 +240,29 @@ class MoreInfoMediaPlayer extends LitElement { return nothing; } - return html` + return html` ${this.stateObj.attributes.sound_mode_list!.map( (soundMode) => - html` ${this.hass.formatEntityAttributeValue( this.stateObj!, "sound_mode", soundMode )} - ` + ` )} - `; + `; } protected _renderGrouping() { @@ -677,6 +679,13 @@ class MoreInfoMediaPlayer extends LitElement { align-self: center; width: 320px; } + + ha-dropdown-item.selected { + font-weight: var(--ha-font-weight-medium); + color: var(--primary-color); + background-color: var(--ha-color-fill-primary-quiet-resting); + --icon-primary-color: var(--primary-color); + } `; private _handleClick(e: MouseEvent): void { @@ -734,8 +743,8 @@ class MoreInfoMediaPlayer extends LitElement { }); } - private _handleSourceClick(e: Event) { - const source = (e.currentTarget as HTMLElement).getAttribute("data-source"); + private _handleSourceChange(e: CustomEvent<{ item: HaDropdownItem }>) { + const source = e.detail.item.value; if (!source || this.stateObj!.attributes.source === source) { return; } @@ -746,10 +755,8 @@ class MoreInfoMediaPlayer extends LitElement { }); } - private _handleSoundModeClick(e: Event) { - const soundMode = (e.currentTarget as HTMLElement).getAttribute( - "data-sound-mode" - ); + private _handleSoundModeChange(ev: CustomEvent<{ item: HaDropdownItem }>) { + const soundMode = ev.detail.item.value; if (!soundMode || this.stateObj!.attributes.sound_mode === soundMode) { return; } diff --git a/src/dialogs/sidebar/dialog-edit-sidebar.ts b/src/dialogs/sidebar/dialog-edit-sidebar.ts index daba7c07ae..74d2390e37 100644 --- a/src/dialogs/sidebar/dialog-edit-sidebar.ts +++ b/src/dialogs/sidebar/dialog-edit-sidebar.ts @@ -7,6 +7,8 @@ import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-alert"; import "../../components/ha-button"; import "../../components/ha-dialog-footer"; +import "../../components/ha-dropdown"; +import "../../components/ha-dropdown-item"; import "../../components/ha-fade-in"; import "../../components/ha-icon-button"; import "../../components/ha-items-display-editor"; @@ -14,12 +16,10 @@ import type { DisplayItem, DisplayValue, } from "../../components/ha-items-display-editor"; -import "../../components/ha-md-button-menu"; -import "../../components/ha-md-menu-item"; -import "../../components/ha-wa-dialog"; import { computePanels } from "../../components/ha-sidebar"; import "../../components/ha-spinner"; import "../../components/ha-svg-icon"; +import "../../components/ha-wa-dialog"; import { fetchFrontendUserData, saveFrontendUserData, @@ -176,22 +176,17 @@ class DialogEditSidebar extends LitElement { : ""} @closed=${this._dialogClosed} > - + - - + + ${this.hass.localize("ui.sidebar.reset_to_defaults")} - - + +
${this._renderContent()}
col.sortable) ? html` - + column.sortable ? html` - ${this._sortColumn === id @@ -292,17 +289,17 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { ` : nothing} ${column.title || column.label} - + ` : nothing )} - + ` : nothing; const groupByMenu = Object.values(this.columns).find((col) => col.groupable) ? html` - + column.groupable ? html` - ${column.title || column.label} - + ` : nothing )} - ${localize("ui.components.subpage-data-table.dont_group_by")} - - - + + ${localize( "ui.components.subpage-data-table.collapse_all_groups" )} - - + ${localize("ui.components.subpage-data-table.expand_all_groups")} - - + + ` : nothing; @@ -399,7 +394,7 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { "ui.components.subpage-data-table.exit_selection_mode" )} > - + - -
- ${localize("ui.components.subpage-data-table.select_all")} -
-
- -
- ${localize( - "ui.components.subpage-data-table.select_none" - )} -
-
- - -
- ${localize( - "ui.components.subpage-data-table.exit_selection_mode" - )} -
-
-
+ + ${localize("ui.components.subpage-data-table.select_all")} + + + ${localize("ui.components.subpage-data-table.select_none")} + + + + ${localize( + "ui.components.subpage-data-table.exit_selection_mode" + )} + + ${this.selected !== undefined ? html`

${localize("ui.components.subpage-data-table.selected", { @@ -612,10 +590,10 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { this._sortColumn = this._sortDirection ? ev.detail.column : undefined; } - private _handleSortBy(ev) { - if (ev.type === "keydown" && ev.key !== "Enter" && ev.key !== " ") return; + private _handleSortBy(ev: CustomEvent<{ item: HaDropdownItem }>) { + ev.preventDefault(); // keep the dropdown open - const columnId = ev.currentTarget.value; + const columnId = ev.detail.item.value; if (!this._sortDirection || this._sortColumn !== columnId) { this._sortDirection = "asc"; } else if (this._sortDirection === "asc") { @@ -631,9 +609,24 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { }); } - private _handleGroupBy = (item) => { - this._setGroupColumn(item.value); - }; + private _handleGroupBy(ev: CustomEvent<{ item: HaDropdownItem }>) { + const group = ev.detail.item.value; + + if (group === "reset") { + this._setGroupColumn(""); + return; + } + if (group === "collapse_all") { + this._collapseAllGroups(); + return; + } + if (group === "expand_all") { + this._expandAllGroups(); + return; + } + + this._setGroupColumn(group); + } private _setGroupColumn(columnId: string) { this._groupColumn = columnId; @@ -669,6 +662,26 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { this._selectMode = true; } + private _handleSelect(ev: CustomEvent<{ item: HaDropdownItem }>) { + const action = ev.detail.item.value; + + if (!action) { + return; + } + + switch (action) { + case "all": + this._selectAll(); + break; + case "none": + this._selectNone(); + break; + case "disable_select_mode": + this._disableSelectMode(); + break; + } + } + private _disableSelectMode = () => { this._selectMode = false; this._dataTable.clearSelection(); @@ -902,9 +915,17 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { flex-direction: column; } - ha-md-button-menu ha-assist-chip { + ha-dropdown ha-assist-chip { --md-assist-chip-trailing-space: 8px; } + + ha-dropdown-item.selected { + border: 1px solid var(--primary-color); + font-weight: var(--ha-font-weight-medium); + color: var(--primary-color); + background-color: var(--ha-color-fill-primary-quiet-resting); + --icon-primary-color: var(--primary-color); + } `; } diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index 28c5929e3a..58786db526 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -1,7 +1,7 @@ +import "@home-assistant/webawesome/dist/components/divider/divider"; import { consume } from "@lit/context"; import { mdiCancel, - mdiChevronRight, mdiDelete, mdiDotsVertical, mdiMenuDown, @@ -43,6 +43,9 @@ import "../../../components/data-table/ha-data-table-labels"; import "../../../components/entity/ha-battery-icon"; import "../../../components/ha-alert"; import "../../../components/ha-check-list-item"; +import "../../../components/ha-dropdown"; +import "../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../components/ha-dropdown-item"; import "../../../components/ha-fab"; import "../../../components/ha-filter-devices"; import "../../../components/ha-filter-floor-areas"; @@ -50,8 +53,6 @@ import "../../../components/ha-filter-integrations"; import "../../../components/ha-filter-labels"; import "../../../components/ha-filter-states"; import "../../../components/ha-icon-button"; -import "../../../components/ha-md-divider"; -import "../../../components/ha-md-menu-item"; import "../../../components/ha-sub-menu"; import { createAreaRegistryEntry } from "../../../data/area/area_registry"; import type { ConfigEntry, SubEntry } from "../../../data/config_entries"; @@ -702,6 +703,70 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) { ]; } + private _renderAreaItems = (slot = "") => + html`${Object.values(this.hass.areas).map( + (area) => + html` + ${area.icon + ? html`` + : html``} + ${area.name} + ` + )} + + ${this.hass.localize( + "ui.panel.config.devices.picker.bulk_actions.no_area" + )} + + + + ${this.hass.localize( + "ui.panel.config.devices.picker.bulk_actions.add_area" + )} + `; + + private _renderLabelItems = (slot = "") => + html`${this._labels?.map((label) => { + const color = label.color ? computeCssColor(label.color) : undefined; + const selected = this._selected.every((deviceId) => + this.hass.devices[deviceId]?.labels.includes(label.label_id) + ); + const partial = + !selected && + this._selected.some((deviceId) => + this.hass.devices[deviceId]?.labels.includes(label.label_id) + ); + return html` + + + ${label.icon + ? html`` + : nothing} + ${label.name} + + `; + })} + + + ${this.hass.localize("ui.panel.config.labels.add_label")} + `; + protected render(): TemplateResult { const { devicesOutput } = this._devicesAndFilterDomains( this.hass.devices, @@ -718,77 +783,6 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) { (this._sizeController.value && this._sizeController.value < 700) || (!this._sizeController.value && this.hass.dockedSidebar === "docked"); - const areaItems = html`${Object.values(this.hass.areas).map( - (area) => - html` - ${area.icon - ? html`` - : html``} -

${area.name}
- ` - )} - -
- ${this.hass.localize( - "ui.panel.config.devices.picker.bulk_actions.no_area" - )} -
-
- - -
- ${this.hass.localize( - "ui.panel.config.devices.picker.bulk_actions.add_area" - )} -
-
`; - - const labelItems = html`${this._labels?.map((label) => { - const color = label.color ? computeCssColor(label.color) : undefined; - const selected = this._selected.every((deviceId) => - this.hass.devices[deviceId]?.labels.includes(label.label_id) - ); - const partial = - !selected && - this._selected.some((deviceId) => - this.hass.devices[deviceId]?.labels.includes(label.label_id) - ); - return html` - - - ${label.icon - ? html`` - : nothing} - ${label.name} - - `; - })} - - -
- ${this.hass.localize("ui.panel.config.labels.add_label")} -
`; - return html` ${!this.narrow - ? html` + ? html` - ${labelItems} - + ${this._renderLabelItems()} + ${areasInOverflow ? nothing - : html` + : html` - ${areaItems} - `}` + ${this._renderAreaItems()} + `}` : nothing} - + ${this.narrow ? html``} ${this.narrow - ? html` - -
- ${this.hass.localize( - "ui.panel.config.automation.picker.bulk_actions.add_label" - )} -
- -
- ${labelItems} -
` + ? html` + ${this.hass.localize( + "ui.panel.config.automation.picker.bulk_actions.add_label" + )} + ${this._renderLabelItems("submenu")} + ` : nothing} ${areasInOverflow - ? html` - -
- ${this.hass.localize( - "ui.panel.config.devices.picker.bulk_actions.move_area" - )} -
- -
- ${areaItems} -
- ` + ? html` + ${this.hass.localize( + "ui.panel.config.devices.picker.bulk_actions.move_area" + )} + ${this._renderAreaItems("submenu")} + + ` : nothing} - - -
- ${this.hass.localize( - "ui.panel.config.devices.picker.bulk_actions.delete_selected.button" - )} -
-
-
+ + ${this.hass.localize( + "ui.panel.config.devices.picker.bulk_actions.delete_selected.button" + )} + +
`; } @@ -1094,12 +1076,22 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) { this._selected = ev.detail.value; } - private _handleBulkArea = (item) => { - const area = item.value; - this._bulkAddArea(area); - }; + private _handleBulkArea(ev: CustomEvent<{ item: HaDropdownItem }>) { + const area = ev.detail.item.value; - private async _bulkAddArea(area: string) { + if (area === "area_create") { + this._bulkCreateArea(); + return; + } + if (area === "area_no") { + this._bulkAddArea(null); + return; + } + + this._bulkAddArea(area.substring(5)); + } + + private async _bulkAddArea(area: string | null) { const promises: Promise[] = []; this._selected.forEach((deviceId) => { promises.push( @@ -1134,10 +1126,20 @@ ${rejected }); }; - private async _handleBulkLabel(ev) { - const label = ev.currentTarget.value; - const action = ev.currentTarget.action; - this._bulkLabel(label, action); + private async _handleBulkLabel(ev: CustomEvent<{ item: HaDropdownItem }>) { + const label = ev.detail.item.value; + + if (label === "label_create") { + this._bulkCreateLabel(); + return; + } + + if (!label) { + return; + } + + const action = (ev.detail.item as any).action; + this._bulkLabel(label.substring(6), action); } private async _bulkLabel(label: string, action: "add" | "remove") { @@ -1251,6 +1253,27 @@ ${rejected this._activeHiddenColumns = ev.detail.hiddenColumns; } + private _handleBulkAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const action = ev.detail.item.value; + + if (!action) { + return; + } + + if (action === "delete_selected") { + this._deleteSelected(); + } + + if (action.startsWith("label_")) { + this._handleBulkLabel(ev); + return; + } + + if (action.startsWith("area_")) { + this._handleBulkArea(ev); + } + } + static get styles(): CSSResultGroup { return [ css` @@ -1273,7 +1296,7 @@ ${rejected ha-assist-chip { --ha-assist-chip-container-shape: 10px; } - ha-md-button-menu ha-assist-chip { + ha-dropdown ha-assist-chip { --md-assist-chip-trailing-space: 8px; } ha-label { diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index d63c26cb6c..dcd6d25695 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -1,3 +1,4 @@ +import "@home-assistant/webawesome/dist/components/divider/divider"; import { consume } from "@lit/context"; import { mdiAlertCircle, @@ -57,6 +58,9 @@ import type { import "../../../components/data-table/ha-data-table-labels"; import "../../../components/ha-alert"; import "../../../components/ha-check-list-item"; +import "../../../components/ha-dropdown"; +import "../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../components/ha-dropdown-item"; import "../../../components/ha-filter-devices"; import "../../../components/ha-filter-domains"; import "../../../components/ha-filter-floor-areas"; @@ -66,8 +70,6 @@ import "../../../components/ha-filter-states"; import "../../../components/ha-filter-voice-assistants"; import "../../../components/ha-icon"; import "../../../components/ha-icon-button"; -import "../../../components/ha-md-divider"; -import "../../../components/ha-md-menu-item"; import "../../../components/ha-sub-menu"; import "../../../components/ha-svg-icon"; import "../../../components/ha-tooltip"; @@ -87,6 +89,7 @@ import type { import { updateEntityRegistryEntry } from "../../../data/entity/entity_registry"; import type { EntitySources } from "../../../data/entity/entity_sources"; import { fetchEntitySourcesWithCache } from "../../../data/entity/entity_sources"; +import { getEntityVoiceAssistantsIds } from "../../../data/expose"; import { HELPERS_CRUD } from "../../../data/helpers_crud"; import type { IntegrationManifest } from "../../../data/integration"; import { @@ -116,12 +119,11 @@ import { isHelperDomain } from "../helpers/const"; import "../integrations/ha-integration-overflow-menu"; import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog"; import { showLabelDetailDialog } from "../labels/show-dialog-label-detail"; -import { getEntityVoiceAssistantsIds } from "../../../data/expose"; -import { getAvailableAssistants } from "../voice-assistants/expose/available-assistants"; import { - getAssistantsTableColumn, getAssistantsSortableKey, + getAssistantsTableColumn, } from "../voice-assistants/expose/assistants-table-column"; +import { getAvailableAssistants } from "../voice-assistants/expose/available-assistants"; export interface StateEntity extends Omit< EntityRegistryEntry, @@ -788,6 +790,44 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { ]; } + private _renderLabelItems = (slot = "") => + html`${this._labels?.map((label) => { + const color = label.color ? computeCssColor(label.color) : undefined; + const selected = this._selected.every((entityId) => + this.hass.entities[entityId]?.labels.includes(label.label_id) + ); + const partial = + !selected && + this._selected.some((entityId) => + this.hass.entities[entityId]?.labels.includes(label.label_id) + ); + return html` + + + ${label.icon + ? html`` + : nothing} + ${label.name} + + `; + })} + + + ${this.hass.localize("ui.panel.config.labels.add_label")} + `; + protected render() { if (!this.hass || this._entities === undefined) { return html` `; @@ -812,53 +852,13 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { [...filteredDomains][0] ); - const labelItems = html` ${this._labels?.map((label) => { - const color = label.color ? computeCssColor(label.color) : undefined; - const selected = this._selected.every((entityId) => - this.hass.entities[entityId]?.labels.includes(label.label_id) - ); - const partial = - !selected && - this._selected.some((entityId) => - this.hass.entities[entityId]?.labels.includes(label.label_id) - ); - return html` - - - ${label.icon - ? html`` - : nothing} - ${label.name} - - `; - })} - - -
- ${this.hass.localize("ui.panel.config.labels.add_label")} -
`; - return html` - Array.isArray(filter) - ? filter.length - : filter && - Object.values(filter).some((val) => - Array.isArray(val) ? val.length : val - ) - ).length - } + .filters=${Object.values(this._filters).filter((filter) => + Array.isArray(filter) + ? filter.length + : filter && + Object.values(filter).some((val) => + Array.isArray(val) ? val.length : val + ) + ).length} selectable .selected=${this._selected.length} .initialGroupColumn=${this._activeGrouping ?? "device_full"} @@ -904,157 +902,125 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { slot="toolbar-icon" > - -${ - !this.narrow - ? html` - - - - ${labelItems} - ` - : nothing -} - - ${ - this.narrow - ? html` - - ` - : html`` - } - - ${ - this.narrow - ? html` - -
- ${this.hass.localize( + ${!this.narrow + ? html` + - - - ${labelItems} - - ` - : nothing - } - - - -
- ${this.hass.localize( - "ui.panel.config.entities.picker.enable_selected.button" - )} -
-
- - -
- ${this.hass.localize( - "ui.panel.config.entities.picker.disable_selected.button" - )} -
-
- - - - -
- ${this.hass.localize( - "ui.panel.config.entities.picker.unhide_selected.button" - )} -
-
- - -
- ${this.hass.localize( - "ui.panel.config.entities.picker.hide_selected.button" - )} -
-
- - - - - -
- ${this.hass.localize( - "ui.panel.config.entities.picker.restore_entity_id_selected.button" - )} -
-
- - - - - -
- ${this.hass.localize( - "ui.panel.config.entities.picker.delete_selected.button" - )} -
-
- - - ${ - Array.isArray(this._filters.config_entry) && - this._filters.config_entry.length - ? html` - ${this.hass.localize( - "ui.panel.config.entities.picker.filtering_by_config_entry" + > + +
+ ${this._renderLabelItems()} +
` + : nothing} + + ${this.narrow + ? html` entry.entry_id === this._filters.config_entry![0] - )?.title || this._filters.config_entry[0]}${this._filters - .config_entry.length === 1 && - Array.isArray(this._filters.sub_entry) && - this._filters.sub_entry.length - ? html` (${this._subEntries?.find( - (entry) => - entry.subentry_id === this._filters.sub_entry![0] - )?.title || this._filters.sub_entry[0]})` - : nothing} - ` - : nothing - } + slot="trigger" + > + + ` + : html``} + ${this.narrow + ? html` + ${this.hass.localize( + "ui.panel.config.automation.picker.bulk_actions.add_label" + )} + + ${this._renderLabelItems("submenu")} + + ` + : nothing} + + + + ${this.hass.localize( + "ui.panel.config.entities.picker.enable_selected.button" + )} + + + + ${this.hass.localize( + "ui.panel.config.entities.picker.disable_selected.button" + )} + + + + + + ${this.hass.localize( + "ui.panel.config.entities.picker.unhide_selected.button" + )} + + + + ${this.hass.localize( + "ui.panel.config.entities.picker.hide_selected.button" + )} + + + + + + + ${this.hass.localize( + "ui.panel.config.entities.picker.restore_entity_id_selected.button" + )} + + + + + + + ${this.hass.localize( + "ui.panel.config.entities.picker.delete_selected.button" + )} + + + ${Array.isArray(this._filters.config_entry) && + this._filters.config_entry.length + ? html` + ${this.hass.localize( + "ui.panel.config.entities.picker.filtering_by_config_entry" + )} + ${this._entries?.find( + (entry) => entry.entry_id === this._filters.config_entry![0] + )?.title || this._filters.config_entry[0]}${this._filters + .config_entry.length === 1 && + Array.isArray(this._filters.sub_entry) && + this._filters.sub_entry.length + ? html` (${this._subEntries?.find( + (entry) => entry.subentry_id === this._filters.sub_entry![0] + )?.title || this._filters.sub_entry[0]})` + : nothing} + ` + : nothing} - ${ - includeAddDeviceFab - ? html` - - ` - : nothing - } + ${includeAddDeviceFab + ? html` + + ` + : nothing} `; } @@ -1396,10 +1358,24 @@ ${ this._clearSelection(); }; - private async _handleBulkLabel(ev) { - const label = ev.currentTarget.value; - const action = ev.currentTarget.action; - await this._bulkLabel(label, action); + private async _handleBulkLabel(ev: CustomEvent<{ item: HaDropdownItem }>) { + ev.preventDefault(); // Prevent the dropdown from closing + + const label = ev.detail.item.value; + + if (!label) { + return; + } + + if (label === "label_create") { + this._bulkCreateLabel(); + return; + } + + const labelId = label.substring(6); + + const action = (ev.detail.item as any).action; + await this._bulkLabel(labelId, action); } private async _bulkLabel(label: string, action: "add" | "remove") { @@ -1590,6 +1566,39 @@ ${rejected this._activeHiddenColumns = ev.detail.hiddenColumns; } + private _handleBulkAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const action = ev.detail.item.value; + + if (!action) { + return; + } + + switch (action) { + case "enable_selected": + this._enableSelected(); + return; + case "disable_selected": + this._disableSelected(); + return; + case "unhide_selected": + this._unhideSelected(); + return; + case "hide_selected": + this._hideSelected(); + return; + case "restore_entity_id_selected": + this._restoreEntityIdSelected(); + return; + case "delete_selected": + this._removeSelected(); + return; + } + + if (action.startsWith("label_")) { + this._handleBulkLabel(ev); + } + } + static get styles(): CSSResultGroup { return [ haStyle, @@ -1659,7 +1668,7 @@ ${rejected ha-assist-chip { --ha-assist-chip-container-shape: 10px; } - ha-md-button-menu ha-assist-chip { + ha-dropdown ha-assist-chip { --md-assist-chip-trailing-space: 8px; } ha-label {