mirror of
https://github.com/home-assistant/frontend.git
synced 2026-02-15 07:25:54 +00:00
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.
This commit is contained in:
@@ -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` <!-- Collapsed representation for small screens -->
|
||||
<ha-md-button-menu
|
||||
@click=${this._handleIconOverflowMenuOpened}
|
||||
positioning="popover"
|
||||
>
|
||||
<ha-dropdown @wa-show=${this._handleIconOverflowMenuOpened}>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
@@ -51,24 +48,17 @@ export class HaIconOverflowMenu extends LitElement {
|
||||
|
||||
${this.items.map((item) =>
|
||||
item.divider
|
||||
? html`<ha-md-divider
|
||||
role="separator"
|
||||
tabindex="-1"
|
||||
></ha-md-divider>`
|
||||
: html`<ha-md-menu-item
|
||||
? html`<wa-divider></wa-divider>`
|
||||
: html`<ha-dropdown-item
|
||||
?disabled=${item.disabled}
|
||||
.clickAction=${item.action}
|
||||
class=${classMap({ warning: Boolean(item.warning) })}
|
||||
@click=${item.action}
|
||||
variant=${item.warning ? "danger" : "default"}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
class=${classMap({ warning: Boolean(item.warning) })}
|
||||
.path=${item.path}
|
||||
></ha-svg-icon>
|
||||
<ha-svg-icon slot="icon" .path=${item.path}></ha-svg-icon>
|
||||
${item.label}
|
||||
</ha-md-menu-item>`
|
||||
</ha-dropdown-item>`
|
||||
)}
|
||||
</ha-md-button-menu>`
|
||||
</ha-dropdown>`
|
||||
: html`
|
||||
<!-- Icon representation for big screens -->
|
||||
${this.items.map((item) =>
|
||||
|
||||
@@ -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`<ha-md-button-menu positioning="popover">
|
||||
return html`<ha-dropdown>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.title=${this.hass.localize(`ui.card.media_player.source`)}
|
||||
.label=${this.hass.localize(`ui.card.media_player.source`)}
|
||||
.path=${mdiLoginVariant}
|
||||
@wa-select=${this._handleSourceChange}
|
||||
>
|
||||
</ha-icon-button>
|
||||
${this.stateObj.attributes.source_list!.map(
|
||||
(source) =>
|
||||
html`<ha-md-menu-item
|
||||
data-source=${source}
|
||||
@click=${this._handleSourceClick}
|
||||
@keydown=${this._handleSourceClick}
|
||||
.selected=${source === this.stateObj?.attributes.source}
|
||||
html`<ha-dropdown-item
|
||||
.value=${source}
|
||||
class=${source === this.stateObj?.attributes.source
|
||||
? "selected"
|
||||
: ""}
|
||||
>
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"source",
|
||||
source
|
||||
)}
|
||||
</ha-md-menu-item>`
|
||||
</ha-dropdown-item>`
|
||||
)}
|
||||
</ha-md-button-menu>`;
|
||||
</ha-dropdown>`;
|
||||
}
|
||||
|
||||
protected _renderSoundMode() {
|
||||
@@ -238,29 +240,29 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`<ha-md-button-menu positioning="popover">
|
||||
return html`<ha-dropdown @wa-select=${this._handleSoundModeChange}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.title=${this.hass.localize(`ui.card.media_player.sound_mode`)}
|
||||
.label=${this.hass.localize(`ui.card.media_player.sound_mode`)}
|
||||
.path=${mdiMusicNoteEighth}
|
||||
>
|
||||
</ha-icon-button>
|
||||
${this.stateObj.attributes.sound_mode_list!.map(
|
||||
(soundMode) =>
|
||||
html`<ha-md-menu-item
|
||||
data-sound-mode=${soundMode}
|
||||
@click=${this._handleSoundModeClick}
|
||||
@keydown=${this._handleSoundModeClick}
|
||||
.selected=${soundMode === this.stateObj?.attributes.sound_mode}
|
||||
html`<ha-dropdown-item
|
||||
.value=${soundMode}
|
||||
class=${soundMode === this.stateObj?.attributes.sound_mode
|
||||
? "selected"
|
||||
: ""}
|
||||
>
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"sound_mode",
|
||||
soundMode
|
||||
)}
|
||||
</ha-md-menu-item>`
|
||||
</ha-dropdown-item>`
|
||||
)}
|
||||
</ha-md-button-menu>`;
|
||||
</ha-dropdown>`;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
<ha-md-button-menu
|
||||
slot="headerActionItems"
|
||||
positioning="popover"
|
||||
anchor-corner="end-end"
|
||||
menu-corner="start-end"
|
||||
>
|
||||
<ha-dropdown slot="headerActionItems" placement="bottom-end">
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-md-menu-item .clickAction=${this._resetToDefaults}>
|
||||
<ha-svg-icon slot="start" .path=${mdiRestart}></ha-svg-icon>
|
||||
<ha-dropdown-item @click=${this._resetToDefaults}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiRestart}></ha-svg-icon>
|
||||
${this.hass.localize("ui.sidebar.reset_to_defaults")}
|
||||
</ha-md-menu-item>
|
||||
</ha-md-button-menu>
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<div class="content">${this._renderContent()}</div>
|
||||
<ha-dialog-footer slot="footer">
|
||||
<ha-button
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import {
|
||||
mdiArrowDown,
|
||||
@@ -28,9 +29,9 @@ import type {
|
||||
import { showDataTableSettingsDialog } from "../components/data-table/show-dialog-data-table-settings";
|
||||
import "../components/ha-dialog";
|
||||
import "../components/ha-dialog-header";
|
||||
import "../components/ha-md-button-menu";
|
||||
import "../components/ha-md-divider";
|
||||
import "../components/ha-md-menu-item";
|
||||
import "../components/ha-dropdown";
|
||||
import "../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../components/ha-dropdown-item";
|
||||
import "../components/search-input-outlined";
|
||||
import { KeyboardShortcutMixin } from "../mixins/keyboard-shortcut-mixin";
|
||||
import type { HomeAssistant, Route } from "../types";
|
||||
@@ -254,7 +255,7 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
const sortByMenu = Object.values(this.columns).find((col) => col.sortable)
|
||||
? html`
|
||||
<ha-md-button-menu positioning="popover">
|
||||
<ha-dropdown @wa-select=${this._handleSortBy}>
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${localize("ui.components.subpage-data-table.sort_by", {
|
||||
@@ -273,12 +274,8 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
${Object.entries(this.columns).map(([id, column]) =>
|
||||
column.sortable
|
||||
? html`
|
||||
<ha-md-menu-item
|
||||
<ha-dropdown-item
|
||||
.value=${id}
|
||||
@click=${this._handleSortBy}
|
||||
@keydown=${this._handleSortBy}
|
||||
keep-open
|
||||
.selected=${id === this._sortColumn}
|
||||
class=${classMap({ selected: id === this._sortColumn })}
|
||||
>
|
||||
${this._sortColumn === id
|
||||
@@ -292,17 +289,17 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
`
|
||||
: nothing}
|
||||
${column.title || column.label}
|
||||
</ha-md-menu-item>
|
||||
</ha-dropdown-item>
|
||||
`
|
||||
: nothing
|
||||
)}
|
||||
</ha-md-button-menu>
|
||||
</ha-dropdown>
|
||||
`
|
||||
: nothing;
|
||||
|
||||
const groupByMenu = Object.values(this.columns).find((col) => col.groupable)
|
||||
? html`
|
||||
<ha-md-button-menu positioning="popover">
|
||||
<ha-dropdown @wa-select=${this._handleGroupBy}>
|
||||
<ha-assist-chip
|
||||
.label=${localize("ui.components.subpage-data-table.group_by", {
|
||||
groupColumn:
|
||||
@@ -320,49 +317,47 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
${Object.entries(this.columns).map(([id, column]) =>
|
||||
column.groupable
|
||||
? html`
|
||||
<ha-md-menu-item
|
||||
<ha-dropdown-item
|
||||
.value=${id}
|
||||
.clickAction=${this._handleGroupBy}
|
||||
.selected=${id === this._groupColumn}
|
||||
class=${classMap({ selected: id === this._groupColumn })}
|
||||
>
|
||||
${column.title || column.label}
|
||||
</ha-md-menu-item>
|
||||
</ha-dropdown-item>
|
||||
`
|
||||
: nothing
|
||||
)}
|
||||
<ha-md-menu-item
|
||||
.value=${""}
|
||||
.clickAction=${this._handleGroupBy}
|
||||
.selected=${!this._groupColumn}
|
||||
<ha-dropdown-item
|
||||
value="reset"
|
||||
class=${classMap({ selected: !this._groupColumn })}
|
||||
>
|
||||
${localize("ui.components.subpage-data-table.dont_group_by")}
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item
|
||||
.clickAction=${this._collapseAllGroups}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item
|
||||
value="collapse_all"
|
||||
.disabled=${!this._groupColumn}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
slot="icon"
|
||||
.path=${mdiUnfoldLessHorizontal}
|
||||
></ha-svg-icon>
|
||||
${localize(
|
||||
"ui.components.subpage-data-table.collapse_all_groups"
|
||||
)}
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item
|
||||
.clickAction=${this._expandAllGroups}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item
|
||||
value="expand_all"
|
||||
.disabled=${!this._groupColumn}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
slot="icon"
|
||||
.path=${mdiUnfoldMoreHorizontal}
|
||||
></ha-svg-icon>
|
||||
${localize("ui.components.subpage-data-table.expand_all_groups")}
|
||||
</ha-md-menu-item>
|
||||
</ha-md-button-menu>
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
`
|
||||
: nothing;
|
||||
|
||||
@@ -399,7 +394,7 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
"ui.components.subpage-data-table.exit_selection_mode"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
<ha-md-button-menu>
|
||||
<ha-dropdown @wa-select=${this._handleSelect}>
|
||||
<ha-assist-chip
|
||||
.label=${localize(
|
||||
"ui.components.subpage-data-table.select"
|
||||
@@ -415,36 +410,19 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon
|
||||
></ha-assist-chip>
|
||||
<ha-md-menu-item
|
||||
.value=${undefined}
|
||||
.clickAction=${this._selectAll}
|
||||
>
|
||||
<div slot="headline">
|
||||
${localize("ui.components.subpage-data-table.select_all")}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item
|
||||
.value=${undefined}
|
||||
.clickAction=${this._selectNone}
|
||||
>
|
||||
<div slot="headline">
|
||||
${localize(
|
||||
"ui.components.subpage-data-table.select_none"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item
|
||||
.value=${undefined}
|
||||
.clickAction=${this._disableSelectMode}
|
||||
>
|
||||
<div slot="headline">
|
||||
${localize(
|
||||
"ui.components.subpage-data-table.exit_selection_mode"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
</ha-md-button-menu>
|
||||
<ha-dropdown-item value="all">
|
||||
${localize("ui.components.subpage-data-table.select_all")}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="none">
|
||||
${localize("ui.components.subpage-data-table.select_none")}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item value="disable_select_mode">
|
||||
${localize(
|
||||
"ui.components.subpage-data-table.exit_selection_mode"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
${this.selected !== undefined
|
||||
? html`<p>
|
||||
${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);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -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`<ha-dropdown-item .value=${`area_${area.area_id}`} .slot=${slot}>
|
||||
${area.icon
|
||||
? html`<ha-icon slot="icon" .icon=${area.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiTextureBox}
|
||||
></ha-svg-icon>`}
|
||||
${area.name}
|
||||
</ha-dropdown-item>`
|
||||
)}
|
||||
<ha-dropdown-item value="area_no" .slot=${slot}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${slot}></wa-divider>
|
||||
<ha-dropdown-item value="area_create" .slot=${slot}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||
)}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
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`<ha-dropdown-item
|
||||
.slot=${slot}
|
||||
.value=${`label_${label.label_id}`}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
keep-open
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="icon"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
reducedTouchTarget
|
||||
></ha-checkbox>
|
||||
<ha-label
|
||||
style=${color ? `--color: ${color}` : ""}
|
||||
.description=${label.description || undefined}
|
||||
>
|
||||
${label.icon
|
||||
? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>`
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-dropdown-item>`;
|
||||
})}
|
||||
<wa-divider .slot=${slot}></wa-divider>
|
||||
<ha-dropdown-item value="label_create" .slot=${slot}>
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
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`<ha-md-menu-item
|
||||
.value=${area.area_id}
|
||||
.clickAction=${this._handleBulkArea}
|
||||
>
|
||||
${area.icon
|
||||
? html`<ha-icon slot="start" .icon=${area.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiTextureBox}
|
||||
></ha-svg-icon>`}
|
||||
<div slot="headline">${area.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-md-menu-item .value=${null} .clickAction=${this._handleBulkArea}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._bulkCreateArea}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>`;
|
||||
|
||||
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`<ha-md-menu-item
|
||||
.value=${label.label_id}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleBulkLabel}
|
||||
keep-open
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="start"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
reducedTouchTarget
|
||||
></ha-checkbox>
|
||||
<ha-label
|
||||
style=${color ? `--color: ${color}` : ""}
|
||||
.description=${label.description}
|
||||
>
|
||||
${label.icon
|
||||
? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>`
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-md-menu-item>`;
|
||||
})}
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._bulkCreateLabel}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</div></ha-md-menu-item
|
||||
>`;
|
||||
|
||||
return html`
|
||||
<hass-tabs-subpage-data-table
|
||||
.hass=${this.hass}
|
||||
@@ -906,7 +900,10 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
></ha-filter-labels>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
? html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleBulkLabel}
|
||||
>
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -918,12 +915,15 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${labelItems}
|
||||
</ha-md-button-menu>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>
|
||||
|
||||
${areasInOverflow
|
||||
? nothing
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
: html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleBulkArea}
|
||||
>
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -935,10 +935,10 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${areaItems}
|
||||
</ha-md-button-menu>`}`
|
||||
${this._renderAreaItems()}
|
||||
</ha-dropdown>`}`
|
||||
: nothing}
|
||||
<ha-md-button-menu has-overflow slot="selection-bar">
|
||||
<ha-dropdown slot="selection-bar" @wa-select=${this._handleBulkAction}>
|
||||
${this.narrow
|
||||
? html`<ha-assist-chip
|
||||
.label=${this.hass.localize(
|
||||
@@ -959,51 +959,33 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
slot="trigger"
|
||||
></ha-icon-button>`}
|
||||
${this.narrow
|
||||
? html` <ha-sub-menu>
|
||||
<ha-md-menu-item slot="item">
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
</div>
|
||||
<ha-svg-icon
|
||||
slot="end"
|
||||
.path=${mdiChevronRight}
|
||||
></ha-svg-icon>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu slot="menu">${labelItems}</ha-md-menu>
|
||||
</ha-sub-menu>`
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
${this._renderLabelItems("submenu")}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${areasInOverflow
|
||||
? html`<ha-sub-menu>
|
||||
<ha-md-menu-item slot="item">
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
</div>
|
||||
<ha-svg-icon
|
||||
slot="end"
|
||||
.path=${mdiChevronRight}
|
||||
></ha-svg-icon>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu slot="menu">${areaItems}</ha-md-menu>
|
||||
</ha-sub-menu>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>`
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
${this._renderAreaItems("submenu")}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>`
|
||||
: nothing}
|
||||
<ha-md-menu-item
|
||||
.clickAction=${this._deleteSelected}
|
||||
<ha-dropdown-item
|
||||
value="delete_selected"
|
||||
.disabled=${!this._selectedCanDelete.length}
|
||||
class="warning"
|
||||
variant="danger"
|
||||
>
|
||||
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.delete_selected.button"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
</ha-md-button-menu>
|
||||
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.delete_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
</hass-tabs-subpage-data-table>
|
||||
`;
|
||||
}
|
||||
@@ -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<DeviceRegistryEntry>[] = [];
|
||||
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 {
|
||||
|
||||
@@ -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`<ha-dropdown-item
|
||||
.slot=${slot}
|
||||
.value=${`label_${label.label_id}`}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="icon"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
reducedTouchTarget
|
||||
></ha-checkbox>
|
||||
<ha-label
|
||||
style=${color ? `--color: ${color}` : ""}
|
||||
.description=${label.description}
|
||||
>
|
||||
${label.icon
|
||||
? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>`
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-dropdown-item>`;
|
||||
})}
|
||||
<wa-divider .slot=${slot}></wa-divider>
|
||||
<ha-dropdown-item .slot=${slot} value="label_create">
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
protected render() {
|
||||
if (!this.hass || this._entities === undefined) {
|
||||
return html` <hass-loading-screen></hass-loading-screen> `;
|
||||
@@ -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`<ha-md-menu-item
|
||||
.value=${label.label_id}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleBulkLabel}
|
||||
keep-open
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="start"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
reducedTouchTarget
|
||||
></ha-checkbox>
|
||||
<ha-label
|
||||
style=${color ? `--color: ${color}` : ""}
|
||||
.description=${label.description}
|
||||
>
|
||||
${label.icon
|
||||
? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>`
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-md-menu-item>`;
|
||||
})}
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._bulkCreateLabel}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</div></ha-md-menu-item
|
||||
>`;
|
||||
|
||||
return html`
|
||||
<hass-tabs-subpage-data-table
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.backPath=${
|
||||
this._searchParms.has("historyBack") ? undefined : "/config"
|
||||
}
|
||||
.backPath=${this._searchParms.has("historyBack")
|
||||
? undefined
|
||||
: "/config"}
|
||||
.route=${this.route}
|
||||
.tabs=${configSections.devices}
|
||||
.columns=${this._columns(this.hass.localize, filteredEntities)}
|
||||
@@ -868,16 +868,14 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
{ number: filteredEntities.length }
|
||||
)}
|
||||
has-filters
|
||||
.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
|
||||
}
|
||||
.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"
|
||||
></ha-integration-overflow-menu>
|
||||
|
||||
|
||||
${
|
||||
!this.narrow
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon slot="trailing-icon" .path=${mdiMenuDown}></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${labelItems}
|
||||
</ha-md-button-menu>`
|
||||
: nothing
|
||||
}
|
||||
<ha-md-button-menu has-overflow slot="selection-bar">
|
||||
${
|
||||
this.narrow
|
||||
? html`<ha-assist-chip
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_action"
|
||||
)}
|
||||
slot="trigger"
|
||||
>
|
||||
<ha-svg-icon slot="trailing-icon" .path=${mdiMenuDown}></ha-svg-icon>
|
||||
</ha-assist-chip>`
|
||||
: html`<ha-icon-button
|
||||
.path=${mdiDotsVertical}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_action"
|
||||
)}
|
||||
slot="trigger"
|
||||
></ha-icon-button>`
|
||||
}
|
||||
<ha-svg-icon
|
||||
slot="trailing-icon"
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon
|
||||
></ha-assist-chip>
|
||||
${
|
||||
this.narrow
|
||||
? html`<ha-sub-menu>
|
||||
<ha-md-menu-item slot="item">
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
${!this.narrow
|
||||
? html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleBulkLabel}
|
||||
>
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
</div>
|
||||
<ha-svg-icon slot="end" .path=${mdiChevronRight}></ha-svg-icon>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu slot="menu">${labelItems}</ha-md-menu>
|
||||
</ha-sub-menu>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>`
|
||||
: nothing
|
||||
}
|
||||
|
||||
<ha-md-menu-item .clickAction=${this._enableSelected}>
|
||||
<ha-svg-icon slot="start" .path=${mdiToggleSwitch}></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.enable_selected.button"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._disableSelected}>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiToggleSwitchOffOutline}
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.disable_selected.button"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
|
||||
<ha-md-menu-item .clickAction=${this._unhideSelected}>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiEye}
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.unhide_selected.button"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._hideSelected}>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiEyeOff}
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.hide_selected.button"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
|
||||
<ha-md-menu-item .clickAction=${this._restoreEntityIdSelected}>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiRestore}
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.restore_entity_id_selected.button"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
|
||||
<ha-md-menu-item .clickAction=${this._removeSelected} class="warning">
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiDelete}
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.delete_selected.button"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
|
||||
</ha-md-button-menu>
|
||||
${
|
||||
Array.isArray(this._filters.config_entry) &&
|
||||
this._filters.config_entry.length
|
||||
? html`<ha-alert slot="filter-pane">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.filtering_by_config_entry"
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="trailing-icon"
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>`
|
||||
: nothing}
|
||||
<ha-dropdown slot="selection-bar" @wa-select=${this._handleBulkAction}>
|
||||
${this.narrow
|
||||
? html`<ha-assist-chip
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_action"
|
||||
)}
|
||||
${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}
|
||||
</ha-alert>`
|
||||
: nothing
|
||||
}
|
||||
slot="trigger"
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="trailing-icon"
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>`
|
||||
: html`<ha-icon-button
|
||||
.path=${mdiDotsVertical}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_action"
|
||||
)}
|
||||
slot="trigger"
|
||||
></ha-icon-button>`}
|
||||
${this.narrow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
<ha-svg-icon
|
||||
slot="end"
|
||||
.path=${mdiChevronRight}
|
||||
></ha-svg-icon>
|
||||
${this._renderLabelItems("submenu")}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>`
|
||||
: nothing}
|
||||
|
||||
<ha-dropdown-item value="enable_selected">
|
||||
<ha-svg-icon slot="icon" .path=${mdiToggleSwitch}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.enable_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="disable_selected">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiToggleSwitchOffOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.disable_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
<ha-dropdown-item value="unhide_selected">
|
||||
<ha-svg-icon slot="icon" .path=${mdiEye}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.unhide_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="hide_selected">
|
||||
<ha-svg-icon slot="icon" .path=${mdiEyeOff}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.hide_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
<ha-dropdown-item value="restore_entity_id_selected">
|
||||
<ha-svg-icon slot="icon" .path=${mdiRestore}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.restore_entity_id_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
<ha-dropdown-item value="delete_selected" variant="danger">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.delete_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
${Array.isArray(this._filters.config_entry) &&
|
||||
this._filters.config_entry.length
|
||||
? html`<ha-alert slot="filter-pane">
|
||||
${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}
|
||||
</ha-alert>`
|
||||
: nothing}
|
||||
<ha-filter-floor-areas
|
||||
.hass=${this.hass}
|
||||
type="entity"
|
||||
@@ -1124,20 +1090,16 @@ ${
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-voice-assistants>
|
||||
${
|
||||
includeAddDeviceFab
|
||||
? html`<ha-fab
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.devices.add_device"
|
||||
)}
|
||||
extended
|
||||
@click=${this._addDevice}
|
||||
slot="fab"
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||
</ha-fab>`
|
||||
: nothing
|
||||
}
|
||||
${includeAddDeviceFab
|
||||
? html`<ha-fab
|
||||
.label=${this.hass.localize("ui.panel.config.devices.add_device")}
|
||||
extended
|
||||
@click=${this._addDevice}
|
||||
slot="fab"
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||
</ha-fab>`
|
||||
: nothing}
|
||||
</hass-tabs-subpage-data-table>
|
||||
`;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user