mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-11 18:47:24 +00:00
Compare commits
4 Commits
copilot/mi
...
config-ent
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca2344eb10 | ||
|
|
6c9f51071c | ||
|
|
0c1f57e2ce | ||
|
|
e573f2012e |
29
src/common/util/configuration-url.ts
Normal file
29
src/common/util/configuration-url.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export interface ProcessedConfigurationUrl {
|
||||
url: string;
|
||||
isLocal: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a processed configuration URL, converting homeassistant:// URLs to local paths
|
||||
* and determining if it should be opened locally or in a new tab.
|
||||
*
|
||||
* @param configurationUrl - The configuration URL to process
|
||||
* @returns Processed URL and whether it's a local link, or null if URL is empty
|
||||
*/
|
||||
export const getConfigurationUrl = (
|
||||
configurationUrl: string | null | undefined
|
||||
): ProcessedConfigurationUrl | null => {
|
||||
if (!configurationUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isHomeAssistant = configurationUrl.startsWith("homeassistant://");
|
||||
const url = isHomeAssistant
|
||||
? configurationUrl.replace("homeassistant://", "/")
|
||||
: configurationUrl;
|
||||
|
||||
return {
|
||||
url,
|
||||
isLocal: isHomeAssistant,
|
||||
};
|
||||
};
|
||||
@@ -27,6 +27,7 @@ export interface ConfigEntry {
|
||||
reason: string | null;
|
||||
error_reason_translation_key: string | null;
|
||||
error_reason_translation_placeholders: Record<string, string> | null;
|
||||
configuration_url?: string | null;
|
||||
}
|
||||
|
||||
export interface SubEntry {
|
||||
|
||||
@@ -16,10 +16,8 @@ import { slugify } from "../../../common/string/slugify";
|
||||
import { groupBy } from "../../../common/util/group-by";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
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-icon-next";
|
||||
import "../../../components/ha-list";
|
||||
@@ -228,23 +226,32 @@ class HaConfigAreaPage extends LitElement {
|
||||
></ha-icon>`
|
||||
: nothing}${area.name}`}
|
||||
>
|
||||
<ha-dropdown slot="toolbar-icon" @wa-select=${this._handleMenuAction}>
|
||||
<ha-button-menu slot="toolbar-icon">
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-dropdown-item value="settings" .entry=${area}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiPencil}></ha-svg-icon>
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.entry=${area}
|
||||
@click=${this._showSettings}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.areas.edit_settings")}
|
||||
</ha-dropdown-item>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPencil}> </ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
<ha-dropdown-item value="delete" variant="danger">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
|
||||
<ha-list-item
|
||||
class="warning"
|
||||
graphic="icon"
|
||||
@click=${this._deleteConfirm}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.areas.editor.delete")}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<ha-svg-icon class="warning" slot="graphic" .path=${mdiDelete}>
|
||||
</ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
|
||||
<div class="container">
|
||||
<div class="column">
|
||||
@@ -606,20 +613,6 @@ class HaConfigAreaPage extends LitElement {
|
||||
this._related = await findRelated(this.hass, "area", this.areaId);
|
||||
}
|
||||
|
||||
private _handleMenuAction(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem & {
|
||||
entry: AreaRegistryEntry;
|
||||
};
|
||||
switch (item.value) {
|
||||
case "settings":
|
||||
this._openDialog(item.entry);
|
||||
break;
|
||||
case "delete":
|
||||
this._deleteConfirm();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _showSettings(ev: MouseEvent) {
|
||||
const entry: AreaRegistryEntry = (ev.currentTarget! as any).entry;
|
||||
this._openDialog(entry);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import {
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
@@ -24,12 +24,10 @@ import {
|
||||
type AreasFloorHierarchy,
|
||||
} from "../../../common/areas/areas-floor-hierarchy";
|
||||
import { formatListWithAnds } from "../../../common/string/format-list";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-floor-icon";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-sortable";
|
||||
import type { HaSortableOptions } from "../../../components/ha-sortable";
|
||||
import "../../../components/ha-svg-icon";
|
||||
@@ -198,43 +196,44 @@ export class HaConfigAreasDashboard extends LitElement {
|
||||
${floor.name}
|
||||
</h2>
|
||||
<div class="actions">
|
||||
<ha-dropdown
|
||||
<ha-button-menu
|
||||
.floor=${floor}
|
||||
@wa-select=${this._handleFloorAction}
|
||||
@action=${this._handleFloorAction}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown-item value="reorder">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
<ha-list-item graphic="icon"
|
||||
><ha-svg-icon
|
||||
.path=${mdiSort}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
slot="graphic"
|
||||
></ha-svg-icon
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.areas.picker.reorder"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item value="edit">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
)}</ha-list-item
|
||||
>
|
||||
<li divider role="separator"></li>
|
||||
<ha-list-item graphic="icon"
|
||||
><ha-svg-icon
|
||||
.path=${mdiPencil}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
slot="graphic"
|
||||
></ha-svg-icon
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.areas.picker.floor.edit_floor"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="delete" variant="danger">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
)}</ha-list-item
|
||||
>
|
||||
<ha-list-item class="warning" graphic="icon"
|
||||
><ha-svg-icon
|
||||
class="warning"
|
||||
.path=${mdiDelete}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
slot="graphic"
|
||||
></ha-svg-icon
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.areas.picker.floor.delete_floor"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
)}</ha-list-item
|
||||
>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
</div>
|
||||
<ha-sortable
|
||||
@@ -274,23 +273,23 @@ export class HaConfigAreasDashboard extends LitElement {
|
||||
)}
|
||||
</h2>
|
||||
<div class="actions">
|
||||
<ha-dropdown
|
||||
@wa-select=${this._handleUnassignedAreasAction}
|
||||
<ha-button-menu
|
||||
@action=${this._handleUnassignedAreasAction}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown-item value="reorder">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
<ha-list-item graphic="icon"
|
||||
><ha-svg-icon
|
||||
.path=${mdiSort}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
slot="graphic"
|
||||
></ha-svg-icon
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.areas.picker.reorder"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
)}</ha-list-item
|
||||
>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
</div>
|
||||
<ha-sortable
|
||||
@@ -534,25 +533,23 @@ export class HaConfigAreasDashboard extends LitElement {
|
||||
}, time);
|
||||
}
|
||||
|
||||
private _handleFloorAction(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
private _handleFloorAction(ev: CustomEvent<ActionDetail>) {
|
||||
const floor = (ev.currentTarget as any).floor;
|
||||
switch (item.value) {
|
||||
case "reorder":
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._showReorderDialog();
|
||||
break;
|
||||
case "edit":
|
||||
case 1:
|
||||
this._editFloor(floor);
|
||||
break;
|
||||
case "delete":
|
||||
case 2:
|
||||
this._deleteFloor(floor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleUnassignedAreasAction(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
if (item.value === "reorder") {
|
||||
private _handleUnassignedAreasAction(ev: CustomEvent<ActionDetail>) {
|
||||
if (ev.detail.index === 0) {
|
||||
this._showReorderDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiChevronRight,
|
||||
mdiCog,
|
||||
mdiContentDuplicate,
|
||||
mdiDelete,
|
||||
@@ -23,7 +23,7 @@ import { differenceInDays } from "date-fns";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
@@ -36,6 +36,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import "../../../components/ha-tooltip";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
@@ -50,9 +51,6 @@ import type {
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/entity/ha-entity-toggle";
|
||||
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-blueprints";
|
||||
import "../../../components/ha-filter-categories";
|
||||
@@ -61,9 +59,13 @@ import "../../../components/ha-filter-entities";
|
||||
import "../../../components/ha-filter-floor-areas";
|
||||
import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-icon-button";
|
||||
|
||||
import "../../../components/ha-md-divider";
|
||||
import "../../../components/ha-md-menu";
|
||||
import type { HaMdMenu } from "../../../components/ha-md-menu";
|
||||
import "../../../components/ha-md-menu-item";
|
||||
import type { HaMdMenuItem } from "../../../components/ha-md-menu-item";
|
||||
import "../../../components/ha-sub-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-tooltip";
|
||||
import { createAreaRegistryEntry } from "../../../data/area_registry";
|
||||
import type { AutomationEntity } from "../../../data/automation";
|
||||
import {
|
||||
@@ -173,6 +175,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg!: EntityRegistryEntry[];
|
||||
|
||||
@state() private _overflowAutomation?: AutomationItem;
|
||||
|
||||
@storage({ key: "automation-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@@ -200,6 +204,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
})
|
||||
private _activeHiddenColumns?: string[];
|
||||
|
||||
@query("#overflow-menu") private _overflowMenu!: HaMdMenu;
|
||||
|
||||
private _sizeController = new ResizeController(this, {
|
||||
callback: (entries) => entries[0]?.contentRect.width,
|
||||
});
|
||||
@@ -362,81 +368,12 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
moveable: false,
|
||||
hideable: false,
|
||||
template: (automation) => html`
|
||||
<ha-dropdown
|
||||
<ha-icon-button
|
||||
.automation=${automation}
|
||||
@wa-select=${this._handleRowOverflowMenu}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown-item value="show-info">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiInformationOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.show_info"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="show-settings">
|
||||
<ha-svg-icon slot="icon" .path=${mdiCog}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.show_settings"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="edit-category">
|
||||
<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.picker.${automation.category ? "edit_category" : "assign_category"}`
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="run-actions">
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlay}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.run")}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="show-trace">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiTransitConnection}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.show_trace"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item value="duplicate">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiContentDuplicate}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.duplicate"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="toggle">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${automation.state === "off"
|
||||
? mdiToggleSwitch
|
||||
: mdiToggleSwitchOffOutline}
|
||||
></ha-svg-icon>
|
||||
${automation.state === "off"
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.enable"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.disable"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="delete" variant="danger">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.delete"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
@click=${this._showOverflowMenu}
|
||||
></ha-icon-button>
|
||||
`,
|
||||
},
|
||||
};
|
||||
@@ -444,38 +381,17 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
);
|
||||
|
||||
private _handleRowOverflowMenu = (ev: CustomEvent) => {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
const automation = (
|
||||
(ev.currentTarget as HTMLElement).closest("ha-dropdown") as any
|
||||
).automation;
|
||||
|
||||
switch (item.value) {
|
||||
case "show-info":
|
||||
this._showInfo(automation);
|
||||
break;
|
||||
case "show-settings":
|
||||
this._showSettings(automation);
|
||||
break;
|
||||
case "edit-category":
|
||||
this._editCategory(automation);
|
||||
break;
|
||||
case "run-actions":
|
||||
this._runActions(automation);
|
||||
break;
|
||||
case "show-trace":
|
||||
this._showTrace(automation);
|
||||
break;
|
||||
case "duplicate":
|
||||
this._duplicate(automation);
|
||||
break;
|
||||
case "toggle":
|
||||
this._toggle(automation);
|
||||
break;
|
||||
case "delete":
|
||||
this._deleteConfirm(automation);
|
||||
break;
|
||||
private _showOverflowMenu = (ev) => {
|
||||
if (
|
||||
this._overflowMenu.open &&
|
||||
ev.target === this._overflowMenu.anchorElement
|
||||
) {
|
||||
this._overflowMenu.close();
|
||||
return;
|
||||
}
|
||||
this._overflowAutomation = ev.target.automation;
|
||||
this._overflowMenu.anchorElement = ev.target;
|
||||
this._overflowMenu.show();
|
||||
};
|
||||
|
||||
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
||||
@@ -493,38 +409,34 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
];
|
||||
}
|
||||
|
||||
private _renderCategoryItems = (submenu = false) =>
|
||||
html`${this._categories?.map(
|
||||
protected render(): TemplateResult {
|
||||
const categoryItems = html`${this._categories?.map(
|
||||
(category) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="move_category"
|
||||
data-category=${category.category_id}
|
||||
html`<ha-md-menu-item
|
||||
.value=${category.category_id}
|
||||
.clickAction=${this._handleBulkCategory}
|
||||
>
|
||||
${category.icon
|
||||
? html`<ha-icon slot="icon" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>`}
|
||||
${category.name}
|
||||
</ha-dropdown-item>`
|
||||
? html`<ha-icon slot="start" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="start" .path=${mdiTag}></ha-svg-icon>`}
|
||||
<div slot="headline">${category.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="__no_category__"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="__create_category__"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</ha-dropdown-item>`;
|
||||
<ha-md-menu-item .value=${null} .clickAction=${this._handleBulkCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._bulkCreateCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</div>
|
||||
</ha-md-menu-item>`;
|
||||
|
||||
private _renderLabelItems = (submenu = false) =>
|
||||
html`${this._labels?.map((label) => {
|
||||
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)
|
||||
@@ -534,14 +446,14 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
this._selected.some((entityId) =>
|
||||
this.hass.entities[entityId]?.labels.includes(label.label_id)
|
||||
);
|
||||
return html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
return html`<ha-md-menu-item
|
||||
.value=${label.label_id}
|
||||
data-action=${selected ? "remove" : "add"}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleBulkLabel}
|
||||
keep-open
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="icon"
|
||||
slot="start"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
reducedTouchTarget
|
||||
@@ -555,50 +467,46 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-dropdown-item>`;
|
||||
</ha-md-menu-item>`;
|
||||
})}
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="__create_label__"
|
||||
@click=${this._bulkCreateLabel}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</ha-dropdown-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
|
||||
>`;
|
||||
|
||||
private _renderAreaItems = (submenu = false) =>
|
||||
html`${Object.values(this.hass.areas).map(
|
||||
const areaItems = html`${Object.values(this.hass.areas).map(
|
||||
(area) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="move_area"
|
||||
data-area=${area.area_id}
|
||||
html`<ha-md-menu-item
|
||||
.value=${area.area_id}
|
||||
.clickAction=${this._handleBulkArea}
|
||||
>
|
||||
${area.icon
|
||||
? html`<ha-icon slot="icon" .icon=${area.icon}></ha-icon>`
|
||||
? html`<ha-icon slot="start" .icon=${area.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="icon"
|
||||
slot="start"
|
||||
.path=${mdiTextureBox}
|
||||
></ha-svg-icon>`}
|
||||
${area.name}
|
||||
</ha-dropdown-item>`
|
||||
<div slot="headline">${area.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="__no_area__">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="__create_area__"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||
)}
|
||||
</ha-dropdown-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>`;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const areasInOverflow =
|
||||
(this._sizeController.value && this._sizeController.value < 900) ||
|
||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||
@@ -619,9 +527,9 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
<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"
|
||||
}
|
||||
id="entity_id"
|
||||
.route=${this.route}
|
||||
.tabs=${configSections.automations}
|
||||
@@ -633,14 +541,16 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
.selected=${this._selected.length}
|
||||
@selection-changed=${this._handleSelectionChanged}
|
||||
has-filters
|
||||
.filters=${Object.values(this._filters).filter((filter) =>
|
||||
Array.isArray(filter.value)
|
||||
? filter.value.length
|
||||
: filter.value &&
|
||||
Object.values(filter.value).some((val) =>
|
||||
Array.isArray(val) ? val.length : val
|
||||
)
|
||||
).length}
|
||||
.filters=${
|
||||
Object.values(this._filters).filter((filter) =>
|
||||
Array.isArray(filter.value)
|
||||
? filter.value.length
|
||||
: filter.value &&
|
||||
Object.values(filter.value).some((val) =>
|
||||
Array.isArray(val) ? val.length : val
|
||||
)
|
||||
).length
|
||||
}
|
||||
.columns=${this._columns(
|
||||
this.narrow,
|
||||
this.hass.localize,
|
||||
@@ -733,31 +643,13 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-blueprints>
|
||||
${!this.narrow
|
||||
? html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.move_category"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="trailing-icon"
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderCategoryItems()}
|
||||
</ha-dropdown>
|
||||
${labelsInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown slot="selection-bar">
|
||||
${
|
||||
!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"
|
||||
"ui.panel.config.automation.picker.bulk_actions.move_category"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon
|
||||
@@ -765,123 +657,179 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>`}
|
||||
${areasInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
${categoryItems}
|
||||
</ha-md-button-menu>
|
||||
${labelsInOverflow
|
||||
? nothing
|
||||
: 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>`}
|
||||
${areasInOverflow
|
||||
? nothing
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="trailing-icon"
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${areaItems}
|
||||
</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-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
>
|
||||
<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(
|
||||
"ui.panel.config.automation.picker.bulk_actions.move_category"
|
||||
)}
|
||||
</div>
|
||||
<ha-svg-icon
|
||||
slot="trailing-icon"
|
||||
.path=${mdiMenuDown}
|
||||
slot="end"
|
||||
.path=${mdiChevronRight}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderAreaItems()}
|
||||
</ha-dropdown>`}`
|
||||
: nothing}
|
||||
<ha-dropdown
|
||||
has-overflow
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
${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>`}
|
||||
${this.narrow
|
||||
? html`<ha-dropdown-item>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu slot="menu">${categoryItems}</ha-md-menu>
|
||||
</ha-sub-menu>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.narrow || labelsInOverflow
|
||||
? 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>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.narrow || 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>`
|
||||
: nothing
|
||||
}
|
||||
<ha-md-menu-item .clickAction=${this._handleBulkEnable}>
|
||||
<ha-svg-icon slot="start" .path=${mdiToggleSwitch}></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.move_category"
|
||||
"ui.panel.config.automation.picker.bulk_actions.enable"
|
||||
)}
|
||||
${this._renderCategoryItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${this.narrow || labelsInOverflow
|
||||
? html`<ha-dropdown-item>
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._handleBulkDisable}>
|
||||
<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiToggleSwitchOffOutline}
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
"ui.panel.config.automation.picker.bulk_actions.disable"
|
||||
)}
|
||||
${this._renderLabelItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${this.narrow || areasInOverflow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
${this._renderAreaItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
<ha-dropdown-item value="enable">
|
||||
<ha-svg-icon slot="icon" .path=${mdiToggleSwitch}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.enable"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="disable">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiToggleSwitchOffOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.disable"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
${!this.automations.length
|
||||
? html`<div class="empty" slot="empty">
|
||||
<ha-svg-icon .path=${mdiRobotHappy}></ha-svg-icon>
|
||||
<h1>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.empty_header"
|
||||
)}
|
||||
</h1>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.empty_text_1"
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.empty_text_2",
|
||||
{ user: this.hass.user?.name || "Alice" }
|
||||
)}
|
||||
</p>
|
||||
<ha-button
|
||||
href=${documentationUrl(this.hass, "/docs/automation/editor/")}
|
||||
target="_blank"
|
||||
appearance="plain"
|
||||
rel="noreferrer"
|
||||
size="small"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.common.learn_more")}
|
||||
<ha-svg-icon slot="end" .path=${mdiOpenInNew}> </ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>`
|
||||
: nothing}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
</ha-md-button-menu>
|
||||
${
|
||||
!this.automations.length
|
||||
? html`<div class="empty" slot="empty">
|
||||
<ha-svg-icon .path=${mdiRobotHappy}></ha-svg-icon>
|
||||
<h1>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.empty_header"
|
||||
)}
|
||||
</h1>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.empty_text_1"
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.empty_text_2",
|
||||
{ user: this.hass.user?.name || "Alice" }
|
||||
)}
|
||||
</p>
|
||||
<ha-button
|
||||
href=${documentationUrl(
|
||||
this.hass,
|
||||
"/docs/automation/editor/"
|
||||
)}
|
||||
target="_blank"
|
||||
appearance="plain"
|
||||
rel="noreferrer"
|
||||
size="small"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.common.learn_more")}
|
||||
<ha-svg-icon slot="end" .path=${mdiOpenInNew}> </ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>`
|
||||
: nothing
|
||||
}
|
||||
<ha-fab
|
||||
slot="fab"
|
||||
.label=${this.hass.localize(
|
||||
@@ -893,6 +841,80 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||
</ha-fab>
|
||||
</hass-tabs-subpage-data-table>
|
||||
<ha-md-menu id="overflow-menu" positioning="fixed">
|
||||
<ha-md-menu-item .clickAction=${this._showInfo}>
|
||||
<ha-svg-icon
|
||||
.path=${mdiInformationOutline}
|
||||
slot="start"
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.automation.editor.show_info")}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
|
||||
<ha-md-menu-item .clickAction=${this._showSettings}>
|
||||
<ha-svg-icon .path=${mdiCog} slot="start"></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.show_settings"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._editCategory}>
|
||||
<ha-svg-icon .path=${mdiTag} slot="start"></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.picker.${this._overflowAutomation?.category ? "edit_category" : "assign_category"}`
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._runActions}>
|
||||
<ha-svg-icon .path=${mdiPlay} slot="start"></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.automation.editor.run")}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._showTrace}>
|
||||
<ha-svg-icon .path=${mdiTransitConnection} slot="start"></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.show_trace"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._duplicate}>
|
||||
<ha-svg-icon .path=${mdiContentDuplicate} slot="start"></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.automation.picker.duplicate")}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._toggle}>
|
||||
<ha-svg-icon
|
||||
.path=${
|
||||
this._overflowAutomation?.state === "off"
|
||||
? mdiToggleSwitch
|
||||
: mdiToggleSwitchOffOutline
|
||||
}
|
||||
slot="start"
|
||||
></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${
|
||||
this._overflowAutomation?.state === "off"
|
||||
? this.hass.localize("ui.panel.config.automation.editor.enable")
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.disable"
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu-item .clickAction=${this._deleteConfirm} class="warning">
|
||||
<ha-svg-icon .path=${mdiDelete} slot="start"></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.automation.picker.delete")}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
</ha-md-menu>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1049,22 +1071,33 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
this._applyFilters();
|
||||
}
|
||||
|
||||
private _showInfo = (automation: AutomationItem) => {
|
||||
private _showInfo = (item: HaMdMenuItem) => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
fireEvent(this, "hass-more-info", { entityId: automation.entity_id });
|
||||
};
|
||||
|
||||
private _showSettings = (automation: AutomationItem) => {
|
||||
private _showSettings = (item: HaMdMenuItem) => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: automation.entity_id,
|
||||
view: "settings",
|
||||
});
|
||||
};
|
||||
|
||||
private _runActions = (automation: AutomationItem) => {
|
||||
private _runActions = (item: HaMdMenuItem) => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
|
||||
triggerAutomationActions(this.hass, automation.entity_id);
|
||||
};
|
||||
|
||||
private _editCategory = (automation: AutomationItem) => {
|
||||
private _editCategory = (item: HaMdMenuItem) => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
|
||||
const entityReg = this._entityReg.find(
|
||||
(reg) => reg.entity_id === automation.entity_id
|
||||
);
|
||||
@@ -1085,7 +1118,10 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
};
|
||||
|
||||
private _showTrace = (automation: AutomationItem) => {
|
||||
private _showTrace = (item: HaMdMenuItem) => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
|
||||
if (!automation.attributes.id) {
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@@ -1099,14 +1135,20 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
};
|
||||
|
||||
private _toggle = async (automation: AutomationItem): Promise<void> => {
|
||||
private _toggle = async (item: HaMdMenuItem): Promise<void> => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
|
||||
const service = automation.state === "off" ? "turn_on" : "turn_off";
|
||||
await this.hass.callService("automation", service, {
|
||||
entity_id: automation.entity_id,
|
||||
});
|
||||
};
|
||||
|
||||
private _deleteConfirm = async (automation: AutomationItem) => {
|
||||
private _deleteConfirm = async (item: HaMdMenuItem) => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
|
||||
showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.automation.picker.delete_confirm_title"
|
||||
@@ -1122,11 +1164,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
};
|
||||
|
||||
private async _delete(automation: AutomationEntity) {
|
||||
private async _delete(automation) {
|
||||
try {
|
||||
if (!automation.attributes.id) {
|
||||
throw new Error("Automation ID is missing");
|
||||
}
|
||||
await deleteAutomation(this.hass, automation.attributes.id);
|
||||
this._selected = this._selected.filter(
|
||||
(entityId) => entityId !== automation.entity_id
|
||||
@@ -1146,11 +1185,11 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
private _duplicate = async (automation: AutomationEntity) => {
|
||||
private _duplicate = async (item: HaMdMenuItem) => {
|
||||
const automation = ((item.parentElement as HaMdMenu)!.anchorElement as any)!
|
||||
.automation;
|
||||
|
||||
try {
|
||||
if (!automation.attributes.id) {
|
||||
throw new Error("Automation ID is missing");
|
||||
}
|
||||
const config = await fetchAutomationFileConfig(
|
||||
this.hass,
|
||||
automation.attributes.id
|
||||
@@ -1222,6 +1261,11 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
private _handleBulkCategory = async (item) => {
|
||||
const category = item.value;
|
||||
this._bulkAddCategory(category);
|
||||
};
|
||||
|
||||
private async _bulkAddCategory(category: string) {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1248,9 +1292,8 @@ ${rejected
|
||||
}
|
||||
|
||||
private async _handleBulkLabel(ev) {
|
||||
ev.stopPropagation();
|
||||
const label = ev.currentTarget.value;
|
||||
const action = ev.currentTarget.dataset.action;
|
||||
const action = ev.currentTarget.action;
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
@@ -1284,6 +1327,11 @@ ${rejected
|
||||
}
|
||||
}
|
||||
|
||||
private _handleBulkArea = (item) => {
|
||||
const area = item.value;
|
||||
this._bulkAddArea(area);
|
||||
};
|
||||
|
||||
private async _bulkAddArea(area: string) {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1319,40 +1367,6 @@ ${rejected
|
||||
});
|
||||
};
|
||||
|
||||
private _handleOverflowMenuSelect = (ev: CustomEvent) => {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
switch (item.value) {
|
||||
case "enable":
|
||||
this._handleBulkEnable();
|
||||
break;
|
||||
case "disable":
|
||||
this._handleBulkDisable();
|
||||
break;
|
||||
case "__create_category__":
|
||||
this._bulkCreateCategory();
|
||||
break;
|
||||
case "__no_category__":
|
||||
this._bulkAddCategory("");
|
||||
break;
|
||||
case "move_category":
|
||||
if (item.dataset.category) {
|
||||
this._bulkAddCategory(item.dataset.category);
|
||||
}
|
||||
break;
|
||||
case "__create_area__":
|
||||
this._bulkCreateArea();
|
||||
break;
|
||||
case "__no_area__":
|
||||
this._bulkAddArea("");
|
||||
break;
|
||||
case "move_area":
|
||||
if (item.dataset.area) {
|
||||
this._bulkAddArea(item.dataset.area);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
private _handleBulkEnable = async () => {
|
||||
const promises: Promise<ServiceCallResponse>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1463,7 +1477,7 @@ ${rejected
|
||||
ha-assist-chip {
|
||||
--ha-assist-chip-container-shape: 10px;
|
||||
}
|
||||
ha-dropdown ha-assist-chip {
|
||||
ha-md-button-menu ha-assist-chip {
|
||||
--md-assist-chip-trailing-space: 8px;
|
||||
}
|
||||
ha-label {
|
||||
|
||||
@@ -6,10 +6,8 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { debounce } from "../../../../common/util/debounce";
|
||||
import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-dropdown";
|
||||
import "../../../../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
|
||||
import "../../../../components/ha-list-item";
|
||||
import "../../../../components/ha-tip";
|
||||
import type {
|
||||
@@ -55,26 +53,26 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
.narrow=${this.narrow}
|
||||
header="Home Assistant Cloud"
|
||||
>
|
||||
<ha-dropdown slot="toolbar-icon" @wa-select=${this._handleMenuAction}>
|
||||
<ha-button-menu slot="toolbar-icon" @action=${this._handleMenuAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-dropdown-item value="reset">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDeleteForever}></ha-svg-icon>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.reset_cloud_data"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="download">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDownload}></ha-svg-icon>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiDeleteForever}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.download_support_package"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiDownload}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
<div class="content">
|
||||
<ha-config-section .isWide=${this.isWide}>
|
||||
<span slot="header">Home Assistant Cloud</span>
|
||||
@@ -299,15 +297,13 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
fireEvent(this, "ha-refresh-cloud-status");
|
||||
}
|
||||
|
||||
private _handleMenuAction(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
switch (item.value) {
|
||||
case "reset":
|
||||
private _handleMenuAction(ev) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._deleteCloudData();
|
||||
break;
|
||||
case "download":
|
||||
case 1:
|
||||
this._downloadSupportPackage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,8 @@ import { customElement, property, query } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../../common/navigate";
|
||||
import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-dropdown";
|
||||
import "../../../../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
|
||||
import "../../../../components/ha-icon-next";
|
||||
import "../../../../components/ha-list";
|
||||
import "../../../../components/ha-list-item";
|
||||
@@ -46,26 +44,26 @@ export class CloudLoginPanel extends LitElement {
|
||||
.narrow=${this.narrow}
|
||||
header="Home Assistant Cloud"
|
||||
>
|
||||
<ha-dropdown slot="toolbar-icon" @wa-select=${this._handleMenuAction}>
|
||||
<ha-button-menu slot="toolbar-icon" @action=${this._handleMenuAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-dropdown-item value="reset">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDeleteForever}></ha-svg-icon>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.reset_cloud_data"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="download">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDownload}></ha-svg-icon>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiDeleteForever}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.download_support_package"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiDownload}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
<div class="content">
|
||||
<ha-config-section .isWide=${this.isWide}>
|
||||
<span slot="header">Home Assistant Cloud</span>
|
||||
@@ -166,15 +164,13 @@ export class CloudLoginPanel extends LitElement {
|
||||
fireEvent(this, "flash-message-changed", { value: "" });
|
||||
}
|
||||
|
||||
private _handleMenuAction(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
switch (item.value) {
|
||||
case "reset":
|
||||
private _handleMenuAction(ev) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._deleteCloudData();
|
||||
break;
|
||||
case "download":
|
||||
case 1:
|
||||
this._downloadSupportPackage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { mdiDotsVertical, mdiRefresh } from "@mdi/js";
|
||||
import type { HassEntities } from "home-assistant-js-websocket";
|
||||
import type { TemplateResult } from "lit";
|
||||
@@ -6,12 +6,13 @@ import { LitElement, css, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-bar";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-check-list-item";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-metric";
|
||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||
import type {
|
||||
@@ -72,24 +73,24 @@ class HaConfigSectionUpdates extends LitElement {
|
||||
.path=${mdiRefresh}
|
||||
@click=${this._checkUpdates}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown @wa-select=${this._handleMenuAction}>
|
||||
<ha-button-menu multi>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown-item
|
||||
type="checkbox"
|
||||
.checked=${this._showSkipped}
|
||||
value="toggle_skipped"
|
||||
<ha-check-list-item
|
||||
left
|
||||
@request-selected=${this._toggleSkipped}
|
||||
.selected=${this._showSkipped}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.updates.show_skipped")}
|
||||
</ha-dropdown-item>
|
||||
</ha-check-list-item>
|
||||
${this._supervisorInfo
|
||||
? html`
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item
|
||||
value="toggle_beta"
|
||||
<li divider role="separator"></li>
|
||||
<ha-list-item
|
||||
@request-selected=${this._toggleBeta}
|
||||
.disabled=${this._supervisorInfo.channel === "dev"}
|
||||
>
|
||||
${this._supervisorInfo.channel === "stable"
|
||||
@@ -97,10 +98,10 @@ class HaConfigSectionUpdates extends LitElement {
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.updates.leave_beta"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-list-item>
|
||||
`
|
||||
: ""}
|
||||
</ha-dropdown>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
<div class="content">
|
||||
<ha-card outlined>
|
||||
@@ -132,21 +133,27 @@ class HaConfigSectionUpdates extends LitElement {
|
||||
this._supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
||||
}
|
||||
|
||||
private _handleMenuAction(ev: CustomEvent): void {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
switch (item.value) {
|
||||
case "toggle_skipped":
|
||||
this._showSkipped = !this._showSkipped;
|
||||
break;
|
||||
case "toggle_beta":
|
||||
if (this._supervisorInfo!.channel === "stable") {
|
||||
showJoinBetaDialog(this, {
|
||||
join: async () => this._setChannel("beta"),
|
||||
});
|
||||
} else {
|
||||
this._setChannel("stable");
|
||||
}
|
||||
break;
|
||||
private _toggleSkipped(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (ev.detail.source !== "property") {
|
||||
return;
|
||||
}
|
||||
|
||||
this._showSkipped = !this._showSkipped;
|
||||
}
|
||||
|
||||
private async _toggleBeta(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._supervisorInfo!.channel === "stable") {
|
||||
showJoinBetaDialog(this, {
|
||||
join: async () => this._setChannel("beta"),
|
||||
});
|
||||
} else {
|
||||
this._setChannel("stable");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import {
|
||||
mdiCloudLock,
|
||||
mdiDotsVertical,
|
||||
@@ -12,12 +13,11 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import "../../../components/chips/ha-assist-chip";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
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-icon-next";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-menu-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-tip";
|
||||
@@ -226,25 +226,25 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMagnify}
|
||||
@click=${this._showQuickBar}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown slot="actionItems" @wa-select=${this._handleMenuAction}>
|
||||
<ha-button-menu slot="actionItems" @action=${this._handleMenuAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-dropdown-item value="check_updates">
|
||||
<ha-svg-icon slot="icon" .path=${mdiRefresh}></ha-svg-icon>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize("ui.panel.config.updates.check_updates")}
|
||||
</ha-dropdown-item>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiRefresh}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
<ha-dropdown-item value="restart">
|
||||
<ha-svg-icon slot="icon" .path=${mdiPower}></ha-svg-icon>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.restart_homeassistant"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPower}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
|
||||
<ha-config-section
|
||||
.narrow=${this.narrow}
|
||||
@@ -371,13 +371,12 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
}
|
||||
|
||||
private async _handleMenuAction(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
switch (item.value) {
|
||||
case "check_updates":
|
||||
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
checkForEntityUpdates(this, this.hass);
|
||||
break;
|
||||
case "restart":
|
||||
case 1:
|
||||
showRestartDialog(this);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { stringCompare } from "../../../common/string/compare";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import { groupBy } from "../../../common/util/group-by";
|
||||
import { getConfigurationUrl } from "../../../common/util/configuration-url";
|
||||
import "../../../components/entity/ha-battery-icon";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button";
|
||||
@@ -1090,17 +1091,12 @@ export class HaConfigDevicePage extends LitElement {
|
||||
|
||||
const deviceActions: DeviceAction[] = [];
|
||||
|
||||
const configurationUrlIsHomeAssistant =
|
||||
device.configuration_url?.startsWith("homeassistant://") || false;
|
||||
const processedUrl = getConfigurationUrl(device.configuration_url);
|
||||
|
||||
const configurationUrl = configurationUrlIsHomeAssistant
|
||||
? device.configuration_url!.replace("homeassistant://", "/")
|
||||
: device.configuration_url;
|
||||
|
||||
if (configurationUrl) {
|
||||
if (processedUrl) {
|
||||
deviceActions.push({
|
||||
href: configurationUrl,
|
||||
target: configurationUrlIsHomeAssistant ? undefined : "_blank",
|
||||
href: processedUrl.url,
|
||||
target: processedUrl.isLocal ? undefined : "_blank",
|
||||
icon: mdiCog,
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.devices.open_configuration_url"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiCancel,
|
||||
mdiChevronRight,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiMenuDown,
|
||||
@@ -38,15 +39,11 @@ import type {
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
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-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";
|
||||
@@ -54,6 +51,9 @@ 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_registry";
|
||||
import type { ConfigEntry, SubEntry } from "../../../data/config_entries";
|
||||
import { getSubEntries, sortConfigEntries } from "../../../data/config_entries";
|
||||
@@ -702,80 +702,6 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
];
|
||||
}
|
||||
|
||||
private _renderAreaItems = (submenu = false) =>
|
||||
html`${Object.values(this.hass.areas).map(
|
||||
(area) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="toggle_area"
|
||||
data-area=${area.area_id}
|
||||
>
|
||||
${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 .slot=${submenu ? "submenu" : ""} value="__no_area__">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="__create_area__"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||
)}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
private _renderLabelItems = (submenu = false) =>
|
||||
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=${submenu ? "submenu" : ""}
|
||||
.value=${label.label_id}
|
||||
data-action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleBulkLabel}
|
||||
>
|
||||
<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=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
@click=${this._bulkCreateLabel}
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const { devicesOutput } = this._devicesAndFilterDomains(
|
||||
this.hass.devices,
|
||||
@@ -792,6 +718,77 @@ 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}
|
||||
@@ -909,7 +906,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
></ha-filter-labels>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-dropdown slot="selection-bar">
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -921,15 +918,12 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>
|
||||
${labelItems}
|
||||
</ha-md-button-menu>
|
||||
|
||||
${areasInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -941,14 +935,10 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderAreaItems()}
|
||||
</ha-dropdown>`}`
|
||||
${areaItems}
|
||||
</ha-md-button-menu>`}`
|
||||
: nothing}
|
||||
<ha-dropdown
|
||||
has-overflow
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
<ha-md-button-menu has-overflow slot="selection-bar">
|
||||
${this.narrow
|
||||
? html`<ha-assist-chip
|
||||
.label=${this.hass.localize(
|
||||
@@ -969,32 +959,51 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
slot="trigger"
|
||||
></ha-icon-button>`}
|
||||
${this.narrow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
${this._renderLabelItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
? 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>`
|
||||
: nothing}
|
||||
${areasInOverflow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
${this._renderAreaItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
? 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>`
|
||||
: nothing}
|
||||
<ha-dropdown-item
|
||||
value="delete"
|
||||
<ha-md-menu-item
|
||||
.clickAction=${this._deleteSelected}
|
||||
.disabled=${!this._selectedCanDelete.length}
|
||||
variant="danger"
|
||||
class="warning"
|
||||
>
|
||||
<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>
|
||||
<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>
|
||||
</hass-tabs-subpage-data-table>
|
||||
`;
|
||||
}
|
||||
@@ -1084,28 +1093,12 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
this._selected = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleOverflowMenuSelect(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
private _handleBulkArea = (item) => {
|
||||
const area = item.value;
|
||||
this._bulkAddArea(area);
|
||||
};
|
||||
|
||||
switch (item.value) {
|
||||
case "delete":
|
||||
this._deleteSelected();
|
||||
break;
|
||||
case "__no_area__":
|
||||
this._bulkAddArea(null);
|
||||
break;
|
||||
case "__create_area__":
|
||||
this._bulkCreateArea();
|
||||
break;
|
||||
case "toggle_area":
|
||||
if (item.dataset.area) {
|
||||
this._bulkAddArea(item.dataset.area);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async _bulkAddArea(area: string | null) {
|
||||
private async _bulkAddArea(area: string) {
|
||||
const promises: Promise<DeviceRegistryEntry>[] = [];
|
||||
this._selected.forEach((deviceId) => {
|
||||
promises.push(
|
||||
@@ -1140,6 +1133,12 @@ ${rejected
|
||||
});
|
||||
};
|
||||
|
||||
private async _handleBulkLabel(ev) {
|
||||
const label = ev.currentTarget.value;
|
||||
const action = ev.currentTarget.action;
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
private async _bulkLabel(label: string, action: "add" | "remove") {
|
||||
const promises: Promise<DeviceRegistryEntry>[] = [];
|
||||
this._selected.forEach((deviceId) => {
|
||||
@@ -1179,13 +1178,6 @@ ${rejected
|
||||
});
|
||||
};
|
||||
|
||||
private async _handleBulkLabel(ev) {
|
||||
ev.stopPropagation();
|
||||
const label = ev.currentTarget.value;
|
||||
const action = ev.currentTarget.dataset.action;
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
private _deleteSelected = () => {
|
||||
showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
@@ -1285,7 +1277,7 @@ ${rejected
|
||||
ha-assist-chip {
|
||||
--ha-assist-chip-container-shape: 10px;
|
||||
}
|
||||
ha-dropdown ha-assist-chip {
|
||||
ha-md-button-menu ha-assist-chip {
|
||||
--md-assist-chip-trailing-space: 8px;
|
||||
}
|
||||
ha-label {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiAlertCircle,
|
||||
mdiCancel,
|
||||
mdiChevronRight,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiEye,
|
||||
@@ -42,7 +42,6 @@ import {
|
||||
PROTOCOL_INTEGRATIONS,
|
||||
protocolIntegrationPicked,
|
||||
} from "../../../common/integrations/protocolIntegrationPicked";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
@@ -56,9 +55,8 @@ import type {
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-check-list-item";
|
||||
import "../../../components/ha-filter-devices";
|
||||
import "../../../components/ha-filter-domains";
|
||||
import "../../../components/ha-filter-floor-areas";
|
||||
@@ -67,6 +65,9 @@ import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-filter-states";
|
||||
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";
|
||||
import type { ConfigEntry, SubEntry } from "../../../data/config_entries";
|
||||
@@ -113,6 +114,7 @@ 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 { slugify } from "../../../common/string/slugify";
|
||||
|
||||
export interface StateEntity extends Omit<
|
||||
EntityRegistryEntry,
|
||||
@@ -746,48 +748,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
];
|
||||
}
|
||||
|
||||
private _renderLabelItems = (submenu = false) =>
|
||||
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=${submenu ? "submenu" : ""}
|
||||
.value=${label.label_id}
|
||||
data-action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleLabelMenuSelect}
|
||||
>
|
||||
<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=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
@click=${this._handleCreateLabel}
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
>
|
||||
${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,13 +772,53 @@ 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)}
|
||||
@@ -828,14 +828,16 @@ 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"}
|
||||
@@ -862,120 +864,157 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
slot="toolbar-icon"
|
||||
></ha-integration-overflow-menu>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-dropdown 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>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>`
|
||||
: nothing}
|
||||
<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
|
||||
${
|
||||
!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"
|
||||
)}
|
||||
>
|
||||
${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>`}
|
||||
${this.narrow
|
||||
? html`<ha-dropdown-item>
|
||||
<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(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
${this._renderLabelItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
</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-dropdown-item value="enable">
|
||||
<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">
|
||||
<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-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-dropdown-item value="unhide">
|
||||
<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">
|
||||
<ha-svg-icon slot="icon" .path=${mdiEyeOff}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.hide_selected.button"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<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>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
|
||||
<ha-dropdown-item value="restore_entity_id">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
|
||||
<ha-dropdown-item value="remove" 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-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"
|
||||
)}
|
||||
${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"
|
||||
@@ -1036,16 +1075,20 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-labels>
|
||||
${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>
|
||||
`;
|
||||
}
|
||||
@@ -1179,44 +1222,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
this._selected = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleLabelMenuSelect(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const item = ev.currentTarget as HaDropdownItem;
|
||||
|
||||
const label = item.value as string;
|
||||
const action = (item as HTMLElement).dataset.action as "add" | "remove";
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
private _handleCreateLabel() {
|
||||
this._bulkCreateLabel();
|
||||
}
|
||||
|
||||
private _handleOverflowMenuSelect(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
|
||||
switch (item.value) {
|
||||
case "enable":
|
||||
this._enableSelected();
|
||||
break;
|
||||
case "disable":
|
||||
this._disableSelected();
|
||||
break;
|
||||
case "unhide":
|
||||
this._unhideSelected();
|
||||
break;
|
||||
case "hide":
|
||||
this._hideSelected();
|
||||
break;
|
||||
case "remove":
|
||||
this._removeSelected();
|
||||
break;
|
||||
case "restore_entity_id":
|
||||
this._restoreEntityIdSelected();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _enableSelected = async () => {
|
||||
showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
@@ -1340,6 +1345,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
this._clearSelection();
|
||||
};
|
||||
|
||||
private async _handleBulkLabel(ev) {
|
||||
const label = ev.currentTarget.value;
|
||||
const action = ev.currentTarget.action;
|
||||
await this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
private async _bulkLabel(label: string, action: "add" | "remove") {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1601,7 +1612,7 @@ ${rejected
|
||||
ha-assist-chip {
|
||||
--ha-assist-chip-container-shape: 10px;
|
||||
}
|
||||
ha-dropdown ha-assist-chip {
|
||||
ha-md-button-menu ha-assist-chip {
|
||||
--md-assist-chip-trailing-space: 8px;
|
||||
}
|
||||
ha-label {
|
||||
|
||||
@@ -1,39 +1,37 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import { consume } from "@lit/context";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import {
|
||||
mdiAlertCircle,
|
||||
mdiCancel,
|
||||
mdiChevronRight,
|
||||
mdiCog,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiDownload,
|
||||
mdiMenuDown,
|
||||
mdiPencilOff,
|
||||
mdiPlus,
|
||||
mdiProgressHelper,
|
||||
mdiPlus,
|
||||
mdiTag,
|
||||
mdiTrashCan,
|
||||
mdiDownload,
|
||||
} from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeAreaName } from "../../../common/entity/compute_area_name";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { computeAreaName } from "../../../common/entity/compute_area_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import type {
|
||||
LocalizeFunc,
|
||||
LocalizeKeys,
|
||||
} from "../../../common/translations/localize";
|
||||
import { extractSearchParam } from "../../../common/url/search-params";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
@@ -45,9 +43,6 @@ import type {
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
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-categories";
|
||||
import "../../../components/ha-filter-devices";
|
||||
@@ -56,12 +51,10 @@ import "../../../components/ha-filter-floor-areas";
|
||||
import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
import "../../../components/ha-md-menu";
|
||||
import "../../../components/ha-md-divider";
|
||||
import "../../../components/ha-state-icon";
|
||||
import "../../../components/ha-sub-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-tooltip";
|
||||
import { getSignedPath } from "../../../data/auth";
|
||||
import type { CategoryRegistryEntry } from "../../../data/category_registry";
|
||||
import {
|
||||
createCategoryRegistryEntry,
|
||||
@@ -79,10 +72,6 @@ import type {
|
||||
DataTableFiltersItems,
|
||||
DataTableFiltersValues,
|
||||
} from "../../../data/data_table_filters";
|
||||
import {
|
||||
fetchDiagnosticHandlers,
|
||||
getConfigEntryDiagnosticsDownloadUrl,
|
||||
} from "../../../data/diagnostics";
|
||||
import type {
|
||||
EntityRegistryEntry,
|
||||
UpdateEntityRegistryEntryResult,
|
||||
@@ -93,7 +82,6 @@ import {
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { fetchEntitySourcesWithCache } from "../../../data/entity_sources";
|
||||
import { HELPERS_CRUD } from "../../../data/helpers_crud";
|
||||
import type { IntegrationManifest } from "../../../data/integration";
|
||||
import {
|
||||
domainToName,
|
||||
@@ -117,15 +105,23 @@ import "../../../layouts/hass-tabs-subpage-data-table";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import { fileDownload } from "../../../util/file_download";
|
||||
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { renderConfigEntryError } from "../integrations/ha-config-integration-page";
|
||||
import "../integrations/ha-integration-overflow-menu";
|
||||
import { renderConfigEntryError } from "../integrations/ha-config-integration-page";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import { isHelperDomain, type HelperDomain } from "./const";
|
||||
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { HELPERS_CRUD } from "../../../data/helpers_crud";
|
||||
import {
|
||||
fetchDiagnosticHandlers,
|
||||
getConfigEntryDiagnosticsDownloadUrl,
|
||||
} from "../../../data/diagnostics";
|
||||
import { getSignedPath } from "../../../data/auth";
|
||||
import { fileDownload } from "../../../util/file_download";
|
||||
|
||||
interface HelperItem {
|
||||
id: string;
|
||||
@@ -610,35 +606,42 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
}
|
||||
|
||||
private _renderCategoryItems = (submenu = false) =>
|
||||
html`${this._categories?.map(
|
||||
protected render(): TemplateResult {
|
||||
if (
|
||||
!this.hass ||
|
||||
this._stateItems === undefined ||
|
||||
this._entityEntries === undefined ||
|
||||
this._configEntries === undefined
|
||||
) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
|
||||
const categoryItems = html`${this._categories?.map(
|
||||
(category) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="move_category"
|
||||
data-category=${category.category_id}
|
||||
html`<ha-md-menu-item
|
||||
.value=${category.category_id}
|
||||
.clickAction=${this._handleBulkCategory}
|
||||
>
|
||||
${category.icon
|
||||
? html`<ha-icon slot="icon" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>`}
|
||||
${category.name}
|
||||
</ha-dropdown-item>`
|
||||
? html`<ha-icon slot="start" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="start" .path=${mdiTag}></ha-svg-icon>`}
|
||||
<div slot="headline">${category.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="no_category">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="create_category"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
private _renderLabelItems = (submenu = false) =>
|
||||
html`${this._labels?.map((label) => {
|
||||
<ha-md-menu-item .value=${null} .clickAction=${this._handleBulkCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._bulkCreateCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</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((entityId) =>
|
||||
this._labelsForEntity(entityId).includes(label.label_id)
|
||||
@@ -648,14 +651,14 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
this._selected.some((entityId) =>
|
||||
this._labelsForEntity(entityId).includes(label.label_id)
|
||||
);
|
||||
return html`<ha-dropdown-item
|
||||
@click=${this._handleLabelMenuSelect}
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
return html`<ha-md-menu-item
|
||||
.value=${label.label_id}
|
||||
data-action=${selected ? "remove" : "add"}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleBulkLabel}
|
||||
keep-open
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="icon"
|
||||
slot="start"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
reducedTouchTarget
|
||||
@@ -669,25 +672,13 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-dropdown-item>`;
|
||||
})}<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
@click=${this._bulkCreateLabel}
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (
|
||||
!this.hass ||
|
||||
this._stateItems === undefined ||
|
||||
this._entityEntries === undefined ||
|
||||
this._configEntries === undefined
|
||||
) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
|
||||
</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>`;
|
||||
const labelsInOverflow =
|
||||
(this._sizeController.value && this._sizeController.value < 700) ||
|
||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||
@@ -789,10 +780,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
></ha-filter-categories>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleMenuSelect}
|
||||
>
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -804,11 +792,11 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderCategoryItems()}
|
||||
</ha-dropdown>
|
||||
${categoryItems}
|
||||
</ha-md-button-menu>
|
||||
${labelsInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown slot="selection-bar">
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -820,15 +808,14 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>`}`
|
||||
${labelItems}
|
||||
</ha-md-button-menu>`}`
|
||||
: nothing}
|
||||
${this.narrow || labelsInOverflow
|
||||
? html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleMenuSelect}
|
||||
>
|
||||
${this.narrow
|
||||
? html`
|
||||
<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"
|
||||
@@ -846,24 +833,50 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
"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.move_category"
|
||||
)}
|
||||
${this._renderCategoryItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${this.narrow || this.hass.dockedSidebar === "docked"
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
${this._renderLabelItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
</ha-dropdown>`
|
||||
></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(
|
||||
"ui.panel.config.automation.picker.bulk_actions.move_category"
|
||||
)}
|
||||
</div>
|
||||
<ha-svg-icon
|
||||
slot="end"
|
||||
.path=${mdiChevronRight}
|
||||
></ha-svg-icon>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu slot="menu">${categoryItems}</ha-md-menu>
|
||||
</ha-sub-menu>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.narrow || this.hass.dockedSidebar === "docked"
|
||||
? 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>`
|
||||
: nothing
|
||||
}
|
||||
</ha-md-button-menu>`
|
||||
: nothing}
|
||||
|
||||
<ha-integration-overflow-menu
|
||||
@@ -1006,7 +1019,12 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
}
|
||||
|
||||
private async _bulkAddCategory(category: string | null) {
|
||||
private _handleBulkCategory = (item) => {
|
||||
const category = item.value;
|
||||
this._bulkAddCategory(category);
|
||||
};
|
||||
|
||||
private async _bulkAddCategory(category: string) {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
promises.push(
|
||||
@@ -1031,6 +1049,12 @@ ${rejected
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleBulkLabel(ev) {
|
||||
const label = ev.currentTarget.value;
|
||||
const action = ev.currentTarget.action;
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
private async _bulkLabel(label: string, action: "add" | "remove") {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1066,32 +1090,6 @@ ${rejected
|
||||
this._selected = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleMenuSelect(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
switch (item.value) {
|
||||
case "no_category":
|
||||
this._bulkAddCategory(null);
|
||||
break;
|
||||
case "create_category":
|
||||
this._bulkCreateCategory();
|
||||
break;
|
||||
case "move_category":
|
||||
if (item.dataset.category) {
|
||||
this._bulkAddCategory(item.dataset.category);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleLabelMenuSelect(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const item = ev.currentTarget as HaDropdownItem;
|
||||
|
||||
const label = item.value as string;
|
||||
const action = (item as HTMLElement).dataset.action as "add" | "remove";
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
@@ -1432,7 +1430,7 @@ ${rejected
|
||||
ha-assist-chip {
|
||||
--ha-assist-chip-container-shape: 10px;
|
||||
}
|
||||
ha-dropdown ha-assist-chip {
|
||||
ha-md-button-menu ha-assist-chip {
|
||||
--md-assist-chip-trailing-space: 8px;
|
||||
}
|
||||
ha-label {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
mdiDotsVertical,
|
||||
mdiDownload,
|
||||
mdiHandExtendedOutline,
|
||||
mdiOpenInNew,
|
||||
mdiPlayCircleOutline,
|
||||
mdiPlus,
|
||||
mdiProgressHelper,
|
||||
@@ -73,6 +74,7 @@ import "./ha-config-entry-device-row";
|
||||
import { renderConfigEntryError } from "./ha-config-integration-page";
|
||||
import "./ha-config-sub-entry-row";
|
||||
import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
||||
import { getConfigurationUrl } from "../../../common/util/configuration-url";
|
||||
import { showToast } from "../../../util/toast";
|
||||
|
||||
@customElement("ha-config-entry-row")
|
||||
@@ -213,34 +215,53 @@ class HaConfigEntryRow extends LitElement {
|
||||
? html`<ha-button slot="end" @click=${this._handleEnable}>
|
||||
${this.hass.localize("ui.common.enable")}
|
||||
</ha-button>`
|
||||
: configPanel &&
|
||||
(item.domain !== "matter" ||
|
||||
isDevVersion(this.hass.config.version)) &&
|
||||
!stateText
|
||||
? html`<a
|
||||
slot="end"
|
||||
href=${`/${configPanel}?config_entry=${item.entry_id}`}
|
||||
><ha-icon-button
|
||||
.path=${mdiCogOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.configure"
|
||||
)}
|
||||
>
|
||||
</ha-icon-button
|
||||
></a>`
|
||||
: item.supports_options
|
||||
? html`
|
||||
<ha-icon-button
|
||||
slot="end"
|
||||
@click=${this._showOptions}
|
||||
.path=${mdiCogOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.configure"
|
||||
)}
|
||||
>
|
||||
</ha-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
: (() => {
|
||||
const processedUrl = getConfigurationUrl(item.configuration_url);
|
||||
|
||||
return html`
|
||||
${processedUrl
|
||||
? html`<a
|
||||
slot="end"
|
||||
href=${processedUrl.url}
|
||||
target=${processedUrl.isLocal ? undefined : "_blank"}
|
||||
rel=${processedUrl.isLocal ? undefined : "noreferrer"}
|
||||
>
|
||||
<ha-icon-button
|
||||
.path=${mdiOpenInNew}
|
||||
.label=${processedUrl.url}
|
||||
></ha-icon-button>
|
||||
</a>`
|
||||
: nothing}
|
||||
${configPanel &&
|
||||
(item.domain !== "matter" ||
|
||||
isDevVersion(this.hass.config.version)) &&
|
||||
!stateText
|
||||
? html`<a
|
||||
slot="end"
|
||||
href=${`/${configPanel}?config_entry=${item.entry_id}`}
|
||||
><ha-icon-button
|
||||
.path=${mdiCogOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.configure"
|
||||
)}
|
||||
>
|
||||
</ha-icon-button
|
||||
></a>`
|
||||
: item.supports_options
|
||||
? html`
|
||||
<ha-icon-button
|
||||
slot="end"
|
||||
@click=${this._showOptions}
|
||||
.path=${mdiCogOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.configure"
|
||||
)}
|
||||
>
|
||||
</ha-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
`;
|
||||
})()}
|
||||
<ha-md-button-menu positioning="popover" slot="end">
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
|
||||
@@ -4,10 +4,8 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { cache } from "lit/directives/cache";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-expansion-panel";
|
||||
import "../../../components/ha-formfield";
|
||||
import "../../../components/ha-icon-button";
|
||||
@@ -502,18 +500,15 @@ export class HassioNetwork extends LitElement {
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
<ha-dropdown
|
||||
@wa-show=${this._handleDNSMenuOpened}
|
||||
@wa-hide=${this._handleDNSMenuClosed}
|
||||
@wa-select=${this._handleDNSMenuSelect}
|
||||
<ha-button-menu
|
||||
@opened=${this._handleDNSMenuOpened}
|
||||
@closed=${this._handleDNSMenuClosed}
|
||||
.version=${version}
|
||||
class="add-nameserver"
|
||||
appearance="filled"
|
||||
size="small"
|
||||
>
|
||||
<ha-button
|
||||
appearance="filled"
|
||||
size="small"
|
||||
slot="trigger"
|
||||
class="add-nameserver"
|
||||
>
|
||||
<ha-button appearance="filled" size="small" slot="trigger">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.network.supervisor.add_dns_server"
|
||||
)}
|
||||
@@ -524,21 +519,21 @@ export class HassioNetwork extends LitElement {
|
||||
</ha-button>
|
||||
${Object.entries(PREDEFINED_DNS[version]).map(
|
||||
([name, addresses]) => html`
|
||||
<ha-dropdown-item
|
||||
value="predefined"
|
||||
<ha-list-item
|
||||
@click=${this._addPredefinedDNS}
|
||||
.version=${version}
|
||||
.addresses=${addresses}
|
||||
>
|
||||
${name}
|
||||
</ha-dropdown-item>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
<ha-dropdown-item value="custom" .version=${version}>
|
||||
<ha-list-item @click=${this._addCustomDNS} .version=${version}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.network.supervisor.custom_dns"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
`
|
||||
: nothing}
|
||||
</ha-expansion-panel>
|
||||
@@ -752,30 +747,27 @@ export class HassioNetwork extends LitElement {
|
||||
this._dnsMenuOpen = false;
|
||||
}
|
||||
|
||||
private _handleDNSMenuSelect(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem & {
|
||||
version: "ipv4" | "ipv6";
|
||||
addresses?: string[];
|
||||
};
|
||||
const version = item.version;
|
||||
private _addPredefinedDNS(ev: Event) {
|
||||
const source = ev.target as any;
|
||||
const version = source.version as "ipv4" | "ipv6";
|
||||
const addresses = source.addresses as string[];
|
||||
if (!this._interface![version]!.nameservers) {
|
||||
this._interface![version]!.nameservers = [];
|
||||
}
|
||||
this._interface![version]!.nameservers!.push(...addresses);
|
||||
this._dirty = true;
|
||||
this.requestUpdate("_interface");
|
||||
}
|
||||
|
||||
if (item.value === "predefined" && item.addresses) {
|
||||
if (!this._interface![version]!.nameservers) {
|
||||
this._interface![version]!.nameservers = [];
|
||||
}
|
||||
this._interface![version]!.nameservers!.push(...item.addresses);
|
||||
this._dirty = true;
|
||||
this.requestUpdate("_interface");
|
||||
return;
|
||||
}
|
||||
if (item.value === "custom") {
|
||||
if (!this._interface![version]!.nameservers) {
|
||||
this._interface![version]!.nameservers = [];
|
||||
}
|
||||
this._interface![version]!.nameservers!.push("");
|
||||
this._dirty = true;
|
||||
this.requestUpdate("_interface");
|
||||
private _addCustomDNS(ev: Event) {
|
||||
const source = ev.target as any;
|
||||
const version = source.version as "ipv4" | "ipv6";
|
||||
if (!this._interface![version]!.nameservers) {
|
||||
this._interface![version]!.nameservers = [];
|
||||
}
|
||||
this._interface![version]!.nameservers!.push("");
|
||||
this._dirty = true;
|
||||
this.requestUpdate("_interface");
|
||||
}
|
||||
|
||||
private _removeNameserver(ev: Event): void {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiChevronRight,
|
||||
mdiCog,
|
||||
mdiContentDuplicate,
|
||||
mdiDelete,
|
||||
@@ -31,7 +31,6 @@ import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
@@ -45,9 +44,6 @@ import type {
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/ha-button";
|
||||
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-categories";
|
||||
import "../../../components/ha-filter-devices";
|
||||
@@ -56,7 +52,11 @@ 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-md-divider";
|
||||
import "../../../components/ha-md-menu";
|
||||
import "../../../components/ha-md-menu-item";
|
||||
import "../../../components/ha-state-icon";
|
||||
import "../../../components/ha-sub-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-tooltip";
|
||||
import { createAreaRegistryEntry } from "../../../data/area_registry";
|
||||
@@ -106,6 +106,7 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
|
||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
|
||||
type SceneItem = SceneEntity & {
|
||||
name: string;
|
||||
@@ -433,8 +434,34 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
];
|
||||
}
|
||||
|
||||
private _renderLabelItems = (submenu = false) =>
|
||||
html` ${this._labels?.map((label) => {
|
||||
protected render(): TemplateResult {
|
||||
const categoryItems = html`${this._categories?.map(
|
||||
(category) =>
|
||||
html`<ha-md-menu-item
|
||||
.value=${category.category_id}
|
||||
.clickAction=${this._handleBulkCategory}
|
||||
>
|
||||
${category.icon
|
||||
? html`<ha-icon slot="start" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="start" .path=${mdiTag}></ha-svg-icon>`}
|
||||
<div slot="headline">${category.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-md-menu-item .value=${null} .clickAction=${this._handleBulkCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</div>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._bulkCreateCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</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((entityId) =>
|
||||
this.hass.entities[entityId]?.labels.includes(label.label_id)
|
||||
@@ -444,14 +471,14 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
this._selected.some((entityId) =>
|
||||
this.hass.entities[entityId]?.labels.includes(label.label_id)
|
||||
);
|
||||
return html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value=${label.label_id}
|
||||
data-action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleLabelMenuSelect}
|
||||
return html`<ha-md-menu-item
|
||||
.value=${label.label_id}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleBulkLabel}
|
||||
keep-open
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="icon"
|
||||
slot="start"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
reducedTouchTarget
|
||||
@@ -465,74 +492,46 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-dropdown-item>`;
|
||||
</ha-md-menu-item>`;
|
||||
})}
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
@click=${this._handleCreateLabel}
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="create-label"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</ha-dropdown-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
|
||||
>`;
|
||||
|
||||
private _renderCategoryItems = (submenu = false) =>
|
||||
html`${this._categories?.map(
|
||||
(category) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="move_category"
|
||||
data-category=${category.category_id}
|
||||
>
|
||||
${category.icon
|
||||
? html`<ha-icon slot="icon" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>`}
|
||||
${category.name}
|
||||
</ha-dropdown-item>`
|
||||
)}
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="no-category">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="create-category"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</ha-dropdown-item>`;
|
||||
|
||||
private _renderAreaItems = (submenu = false) =>
|
||||
html`${Object.values(this.hass.areas).map(
|
||||
const areaItems = html`${Object.values(this.hass.areas).map(
|
||||
(area) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="move_area"
|
||||
data-area=${area.area_id}
|
||||
html`<ha-md-menu-item
|
||||
.value=${area.area_id}
|
||||
.clickAction=${this._handleBulkArea}
|
||||
>
|
||||
${area.icon
|
||||
? html`<ha-icon slot="icon" .icon=${area.icon}></ha-icon>`
|
||||
? html`<ha-icon slot="start" .icon=${area.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="icon"
|
||||
slot="start"
|
||||
.path=${mdiTextureBox}
|
||||
></ha-svg-icon>`}
|
||||
${area.name}
|
||||
</ha-dropdown-item>`
|
||||
<div slot="headline">${area.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="no-area">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="create-area">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||
)}
|
||||
</ha-dropdown-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>`;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const areasInOverflow =
|
||||
(this._sizeController.value && this._sizeController.value < 900) ||
|
||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||
@@ -655,10 +654,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
></ha-filter-categories>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -670,11 +666,11 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderCategoryItems()}
|
||||
</ha-dropdown>
|
||||
${categoryItems}
|
||||
</ha-md-button-menu>
|
||||
${labelsInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown slot="selection-bar">
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -686,14 +682,11 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>`}
|
||||
${labelItems}
|
||||
</ha-md-button-menu>`}
|
||||
${areasInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -705,15 +698,14 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderAreaItems()}
|
||||
</ha-dropdown>`}`
|
||||
${areaItems}
|
||||
</ha-md-button-menu>`}`
|
||||
: nothing}
|
||||
${this.narrow || areasInOverflow
|
||||
? html` <ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
${this.narrow
|
||||
? html`
|
||||
<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"
|
||||
@@ -731,32 +723,68 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
"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.move_category"
|
||||
)}
|
||||
${this._renderCategoryItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${this.narrow || labelsInOverflow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
${this._renderLabelItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${this.narrow || areasInOverflow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
${this._renderAreaItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
</ha-dropdown>`
|
||||
></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(
|
||||
"ui.panel.config.automation.picker.bulk_actions.move_category"
|
||||
)}
|
||||
</div>
|
||||
<ha-svg-icon
|
||||
slot="end"
|
||||
.path=${mdiChevronRight}
|
||||
></ha-svg-icon>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu slot="menu">${categoryItems}</ha-md-menu>
|
||||
</ha-sub-menu>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.narrow || labelsInOverflow
|
||||
? 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>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.narrow || 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>`
|
||||
: nothing
|
||||
}
|
||||
</ha-md-button-menu>`
|
||||
: nothing}
|
||||
${!this.scenes.length
|
||||
? html`<div class="empty" slot="empty">
|
||||
@@ -927,52 +955,12 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
private _handleLabelMenuSelect = (ev: CustomEvent) => {
|
||||
ev.stopPropagation();
|
||||
const item = ev.currentTarget as HaDropdownItem & {
|
||||
dataset: { action?: string };
|
||||
};
|
||||
const action = item.dataset.action as "add" | "remove";
|
||||
this._bulkLabel(item.value, action);
|
||||
private _handleBulkCategory = (item) => {
|
||||
const category = item.value;
|
||||
this._bulkAddCategory(category);
|
||||
};
|
||||
|
||||
private _handleCreateLabel = () => {
|
||||
this._bulkCreateLabel();
|
||||
};
|
||||
|
||||
private _handleOverflowMenuSelect = (ev: CustomEvent) => {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
|
||||
switch (item.value) {
|
||||
case "create-category":
|
||||
this._bulkCreateCategory();
|
||||
break;
|
||||
case "no-category":
|
||||
this._bulkAddCategory(null);
|
||||
break;
|
||||
case "create-label":
|
||||
this._bulkCreateLabel();
|
||||
break;
|
||||
case "create-area":
|
||||
this._bulkCreateArea();
|
||||
break;
|
||||
case "no-area":
|
||||
this._bulkAddArea(null);
|
||||
break;
|
||||
case "move_category":
|
||||
if (item.dataset.category) {
|
||||
this._bulkAddCategory(item.dataset.category);
|
||||
}
|
||||
break;
|
||||
case "move_area":
|
||||
if (item.dataset.area) {
|
||||
this._bulkAddArea(item.dataset.area);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
private async _bulkAddCategory(category: string | null) {
|
||||
private async _bulkAddCategory(category: string) {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
promises.push(
|
||||
@@ -997,6 +985,12 @@ ${rejected
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleBulkLabel(ev) {
|
||||
const label = ev.currentTarget.value;
|
||||
const action = ev.currentTarget.action;
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
private async _bulkLabel(label: string, action: "add" | "remove") {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1027,7 +1021,12 @@ ${rejected
|
||||
}
|
||||
}
|
||||
|
||||
private async _bulkAddArea(area: string | null) {
|
||||
private _handleBulkArea = (item) => {
|
||||
const area = item.value;
|
||||
this._bulkAddArea(area);
|
||||
};
|
||||
|
||||
private async _bulkAddArea(area: string) {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
promises.push(
|
||||
@@ -1232,7 +1231,7 @@ ${rejected
|
||||
ha-assist-chip {
|
||||
--ha-assist-chip-container-shape: 10px;
|
||||
}
|
||||
ha-dropdown ha-assist-chip {
|
||||
ha-md-button-menu ha-assist-chip {
|
||||
--md-assist-chip-trailing-space: 8px;
|
||||
}
|
||||
ha-label {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { consume } from "@lit/context";
|
||||
|
||||
import type { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import {
|
||||
mdiCog,
|
||||
mdiContentDuplicate,
|
||||
@@ -32,10 +32,8 @@ import "../../../components/entity/ha-entities-picker";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-area-picker";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon-picker";
|
||||
@@ -229,66 +227,78 @@ export class HaSceneEditor extends PreventUnsavedMixin(
|
||||
? computeStateName(this._scene)
|
||||
: this.hass.localize("ui.panel.config.scene.editor.default_name")}
|
||||
>
|
||||
<ha-dropdown slot="toolbar-icon" @wa-select=${this._handleMenuAction}>
|
||||
<ha-button-menu
|
||||
slot="toolbar-icon"
|
||||
@action=${this._handleMenuAction}
|
||||
activatable
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-dropdown-item
|
||||
value="apply"
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.disabled=${!this.sceneId || this._mode === "live"}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlay}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.scene.picker.apply")}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="info" .disabled=${!this.sceneId}>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPlay}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
<ha-list-item graphic="icon" .disabled=${!this.sceneId}>
|
||||
${this.hass.localize("ui.panel.config.scene.picker.show_info")}
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
slot="graphic"
|
||||
.path=${mdiInformationOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.scene.picker.show_info")}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="settings" .disabled=${!this.sceneId}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiCog}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
<ha-list-item graphic="icon" .disabled=${!this.sceneId}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.show_settings"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiCog}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
<ha-dropdown-item value="category" .disabled=${!this.sceneId}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>
|
||||
<ha-list-item graphic="icon" .disabled=${!this.sceneId}>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.scene.picker.${this._getCategory(this._entityRegistryEntries, this._scene?.entity_id) ? "edit_category" : "assign_category"}`
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiTag}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
<ha-dropdown-item value="toggle_yaml">
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.edit_${this._mode !== "yaml" ? "yaml" : "ui"}`
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPlaylistEdit}></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<ha-dropdown-item value="duplicate" .disabled=${!this.sceneId}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiContentDuplicate}></ha-svg-icon>
|
||||
<ha-list-item .disabled=${!this.sceneId} graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.scene.picker.duplicate_scene"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${mdiContentDuplicate}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
|
||||
<ha-dropdown-item
|
||||
value="delete"
|
||||
<ha-list-item
|
||||
.disabled=${!this.sceneId}
|
||||
.variant=${this.sceneId ? "danger" : "default"}
|
||||
class=${classMap({ warning: Boolean(this.sceneId) })}
|
||||
graphic="icon"
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.scene.picker.delete_scene")}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
<ha-svg-icon
|
||||
class=${classMap({ warning: Boolean(this.sceneId) })}
|
||||
slot="graphic"
|
||||
.path=${mdiDelete}
|
||||
>
|
||||
</ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
${this._errors ? html` <div class="errors">${this._errors}</div> ` : ""}
|
||||
${this._mode === "yaml" ? this._renderYamlMode() : this._renderUiMode()}
|
||||
<ha-fab
|
||||
@@ -642,25 +652,24 @@ export class HaSceneEditor extends PreventUnsavedMixin(
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleMenuAction(ev: CustomEvent) {
|
||||
const item = ev.detail.item as HaDropdownItem;
|
||||
switch (item.value) {
|
||||
case "apply":
|
||||
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
activateScene(this.hass, this._scene!.entity_id);
|
||||
break;
|
||||
case "info":
|
||||
case 1:
|
||||
fireEvent(this, "hass-more-info", { entityId: this._scene!.entity_id });
|
||||
break;
|
||||
case "settings":
|
||||
case 2:
|
||||
showMoreInfoDialog(this, {
|
||||
entityId: this._scene!.entity_id,
|
||||
view: "settings",
|
||||
});
|
||||
break;
|
||||
case "category":
|
||||
case 3:
|
||||
this._editCategory(this._scene!);
|
||||
break;
|
||||
case "toggle_yaml":
|
||||
case 4:
|
||||
if (this._mode === "yaml") {
|
||||
this._initEntities(this._config!);
|
||||
this._exitYamlMode();
|
||||
@@ -668,10 +677,10 @@ export class HaSceneEditor extends PreventUnsavedMixin(
|
||||
this._enterYamlMode();
|
||||
}
|
||||
break;
|
||||
case "duplicate":
|
||||
case 5:
|
||||
this._duplicate();
|
||||
break;
|
||||
case "delete":
|
||||
case 6:
|
||||
this._deleteTapped();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiChevronRight,
|
||||
mdiCog,
|
||||
mdiContentDuplicate,
|
||||
mdiDelete,
|
||||
@@ -34,6 +34,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import "../../../components/ha-tooltip";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
@@ -46,9 +47,6 @@ import type {
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
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-blueprints";
|
||||
import "../../../components/ha-filter-categories";
|
||||
@@ -58,8 +56,11 @@ 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-md-divider";
|
||||
import "../../../components/ha-md-menu";
|
||||
import "../../../components/ha-md-menu-item";
|
||||
import "../../../components/ha-sub-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-tooltip";
|
||||
import { createAreaRegistryEntry } from "../../../data/area_registry";
|
||||
import type { CategoryRegistryEntry } from "../../../data/category_registry";
|
||||
import {
|
||||
@@ -418,35 +419,33 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
];
|
||||
}
|
||||
|
||||
private _renderCategoryItems = (submenu = false) =>
|
||||
html`${this._categories?.map(
|
||||
protected render(): TemplateResult {
|
||||
const categoryItems = html`${this._categories?.map(
|
||||
(category) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="move_category"
|
||||
data-category=${category.category_id}
|
||||
html`<ha-md-menu-item
|
||||
.value=${category.category_id}
|
||||
.clickAction=${this._handleBulkCategory}
|
||||
>
|
||||
${category.icon
|
||||
? html`<ha-icon slot="icon" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>`}
|
||||
${category.name}
|
||||
</ha-dropdown-item>`
|
||||
? html`<ha-icon slot="start" .icon=${category.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon slot="start" .path=${mdiTag}></ha-svg-icon>`}
|
||||
<div slot="headline">${category.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="no-category">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="create-category"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</ha-dropdown-item>`;
|
||||
<ha-md-menu-item .value=${null} .clickAction=${this._handleBulkCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||
)}
|
||||
</div> </ha-md-menu-item
|
||||
><ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||
<ha-md-menu-item .clickAction=${this._bulkCreateCategory}>
|
||||
<div slot="headline">
|
||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||
</div>
|
||||
</ha-md-menu-item>`;
|
||||
|
||||
private _renderLabelItems = (submenu = false) =>
|
||||
html`${this._labels?.map((label) => {
|
||||
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)
|
||||
@@ -456,13 +455,15 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
this._selected.some((entityId) =>
|
||||
this.hass.entities[entityId]?.labels.includes(label.label_id)
|
||||
);
|
||||
return html`<ha-dropdown-item
|
||||
@click=${this._handleLabelMenuSelect}
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value=${label.label_id}
|
||||
data-action=${selected ? "remove" : "add"}
|
||||
><ha-checkbox
|
||||
slot="icon"
|
||||
return html`<ha-md-menu-item
|
||||
.value=${label.label_id}
|
||||
.action=${selected ? "remove" : "add"}
|
||||
@click=${this._handleBulkLabel}
|
||||
keep-open
|
||||
reducedTouchTarget
|
||||
>
|
||||
<ha-checkbox
|
||||
slot="start"
|
||||
.checked=${selected}
|
||||
.indeterminate=${partial}
|
||||
></ha-checkbox>
|
||||
@@ -475,47 +476,46 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
: nothing}
|
||||
${label.name}
|
||||
</ha-label>
|
||||
</ha-dropdown-item>`;
|
||||
</ha-md-menu-item>`;
|
||||
})}
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item
|
||||
@click=${this._bulkCreateLabel}
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="create-label"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||
</ha-dropdown-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
|
||||
>`;
|
||||
|
||||
private _renderAreaItems = (submenu = false) =>
|
||||
html`${Object.values(this.hass.areas).map(
|
||||
const areaItems = html`${Object.values(this.hass.areas).map(
|
||||
(area) =>
|
||||
html`<ha-dropdown-item
|
||||
.slot=${submenu ? "submenu" : ""}
|
||||
value="move_area"
|
||||
data-area=${area.area_id}
|
||||
html`<ha-md-menu-item
|
||||
.value=${area.area_id}
|
||||
.clickAction=${this._handleBulkArea}
|
||||
>
|
||||
${area.icon
|
||||
? html`<ha-icon slot="icon" .icon=${area.icon}></ha-icon>`
|
||||
? html`<ha-icon slot="start" .icon=${area.icon}></ha-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="icon"
|
||||
slot="start"
|
||||
.path=${mdiTextureBox}
|
||||
></ha-svg-icon>`}
|
||||
${area.name}
|
||||
</ha-dropdown-item>`
|
||||
<div slot="headline">${area.name}</div>
|
||||
</ha-md-menu-item>`
|
||||
)}
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="no-area">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider .slot=${submenu ? "submenu" : ""}></wa-divider>
|
||||
<ha-dropdown-item .slot=${submenu ? "submenu" : ""} value="create-area">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||
)}
|
||||
</ha-dropdown-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>`;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const areasInOverflow =
|
||||
(this._sizeController.value && this._sizeController.value < 900) ||
|
||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||
@@ -647,10 +647,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
></ha-filter-blueprints>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -662,11 +659,11 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderCategoryItems()}
|
||||
</ha-dropdown>
|
||||
${categoryItems}
|
||||
</ha-md-button-menu>
|
||||
${labelsInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown slot="selection-bar">
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -678,14 +675,11 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderLabelItems()}
|
||||
</ha-dropdown>`}
|
||||
${labelItems}
|
||||
</ha-md-button-menu>`}
|
||||
${areasInOverflow
|
||||
? nothing
|
||||
: html`<ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
: html`<ha-md-button-menu slot="selection-bar">
|
||||
<ha-assist-chip
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize(
|
||||
@@ -697,15 +691,14 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
.path=${mdiMenuDown}
|
||||
></ha-svg-icon>
|
||||
</ha-assist-chip>
|
||||
${this._renderAreaItems()}
|
||||
</ha-dropdown>`}`
|
||||
${areaItems}
|
||||
</ha-md-button-menu>`}`
|
||||
: nothing}
|
||||
${this.narrow || areasInOverflow
|
||||
? html` <ha-dropdown
|
||||
slot="selection-bar"
|
||||
@wa-select=${this._handleOverflowMenuSelect}
|
||||
>
|
||||
${this.narrow
|
||||
? html`
|
||||
<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"
|
||||
@@ -723,32 +716,68 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
"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.move_category"
|
||||
)}
|
||||
${this._renderCategoryItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${this.narrow || labelsInOverflow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.picker.bulk_actions.add_label"
|
||||
)}
|
||||
${this._renderLabelItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${this.narrow || areasInOverflow
|
||||
? html`<ha-dropdown-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.picker.bulk_actions.move_area"
|
||||
)}
|
||||
${this._renderAreaItems(true)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
</ha-dropdown>`
|
||||
></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(
|
||||
"ui.panel.config.automation.picker.bulk_actions.move_category"
|
||||
)}
|
||||
</div>
|
||||
<ha-svg-icon
|
||||
slot="end"
|
||||
.path=${mdiChevronRight}
|
||||
></ha-svg-icon>
|
||||
</ha-md-menu-item>
|
||||
<ha-md-menu slot="menu">${categoryItems}</ha-md-menu>
|
||||
</ha-sub-menu>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.narrow || labelsInOverflow
|
||||
? 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>`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.narrow || 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>`
|
||||
: nothing
|
||||
}
|
||||
</ha-md-button-menu>`
|
||||
: nothing}
|
||||
${!this.scripts.length
|
||||
? html` <div class="empty" slot="empty">
|
||||
@@ -966,46 +995,9 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
this._selected = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleLabelMenuSelect = (ev: CustomEvent) => {
|
||||
ev.stopPropagation();
|
||||
const item = ev.currentTarget as HaDropdownItem & {
|
||||
dataset: { action?: string };
|
||||
};
|
||||
const action = item.dataset.action as "add" | "remove";
|
||||
this._bulkLabel(item.value, action);
|
||||
};
|
||||
|
||||
private _handleOverflowMenuSelect = (ev: CustomEvent) => {
|
||||
const item = ev.detail.item as HaDropdownItem & {
|
||||
dataset: { action?: string };
|
||||
};
|
||||
switch (item.value) {
|
||||
case "create-category":
|
||||
this._bulkCreateCategory();
|
||||
break;
|
||||
case "no-category":
|
||||
this._bulkAddCategory(null!);
|
||||
break;
|
||||
case "create-label":
|
||||
this._bulkCreateLabel();
|
||||
break;
|
||||
case "create-area":
|
||||
this._bulkCreateArea();
|
||||
break;
|
||||
case "no-area":
|
||||
this._bulkAddArea(null!);
|
||||
break;
|
||||
case "move_area":
|
||||
if (item.dataset.area) {
|
||||
this._bulkAddArea(item.dataset.area);
|
||||
}
|
||||
break;
|
||||
case "move_category":
|
||||
if (item.dataset.category) {
|
||||
this._bulkAddCategory(item.dataset.category);
|
||||
}
|
||||
break;
|
||||
}
|
||||
private _handleBulkCategory = (item) => {
|
||||
const category = item.value;
|
||||
this._bulkAddCategory(category);
|
||||
};
|
||||
|
||||
private async _bulkAddCategory(category: string) {
|
||||
@@ -1033,6 +1025,12 @@ ${rejected
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleBulkLabel(ev) {
|
||||
const label = ev.currentTarget.value;
|
||||
const action = ev.currentTarget.action;
|
||||
this._bulkLabel(label, action);
|
||||
}
|
||||
|
||||
private async _bulkLabel(label: string, action: "add" | "remove") {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1237,6 +1235,11 @@ ${rejected
|
||||
});
|
||||
};
|
||||
|
||||
private _handleBulkArea = (item) => {
|
||||
const area = item.value;
|
||||
this._bulkAddArea(area);
|
||||
};
|
||||
|
||||
private async _bulkAddArea(area: string) {
|
||||
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||
this._selected.forEach((entityId) => {
|
||||
@@ -1319,7 +1322,7 @@ ${rejected
|
||||
ha-assist-chip {
|
||||
--ha-assist-chip-container-shape: 10px;
|
||||
}
|
||||
ha-dropdown ha-assist-chip {
|
||||
ha-md-button-menu ha-assist-chip {
|
||||
--md-assist-chip-trailing-space: 8px;
|
||||
}
|
||||
ha-label {
|
||||
|
||||
@@ -88,18 +88,16 @@ export class HuiEnergyGasGraphCard
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
${this._config.title
|
||||
? html` <div class="card-header">
|
||||
<span>${this._config.title}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>`
|
||||
: nothing}
|
||||
<div class="card-header">
|
||||
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>
|
||||
<div
|
||||
class="content ${classMap({
|
||||
"has-header": !!this._config.title,
|
||||
|
||||
@@ -90,18 +90,16 @@ export class HuiEnergySolarGraphCard
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
${this._config.title
|
||||
? html` <div class="card-header">
|
||||
<span>${this._config.title}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${formatNumber(this._total, this.hass.locale)} kWh
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>`
|
||||
: nothing}
|
||||
<div class="card-header">
|
||||
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${formatNumber(this._total, this.hass.locale)} kWh
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>
|
||||
<div
|
||||
class="content ${classMap({
|
||||
"has-header": !!this._config.title,
|
||||
|
||||
@@ -103,21 +103,19 @@ export class HuiEnergyUsageGraphCard
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
${this._config.title
|
||||
? html` <div class="card-header">
|
||||
<span>${this._config.title}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.total_usage",
|
||||
{ num: formatNumber(this._total, this.hass.locale) }
|
||||
)}
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>`
|
||||
: nothing}
|
||||
<div class="card-header">
|
||||
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.total_usage",
|
||||
{ num: formatNumber(this._total, this.hass.locale) }
|
||||
)}
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>
|
||||
<div
|
||||
class="content ${classMap({
|
||||
"has-header": !!this._config.title,
|
||||
|
||||
@@ -88,18 +88,16 @@ export class HuiEnergyWaterGraphCard
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
${this._config.title
|
||||
? html` <div class="card-header">
|
||||
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>`
|
||||
: nothing}
|
||||
<div class="card-header">
|
||||
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||
${this._total
|
||||
? html`<hui-energy-graph-chip
|
||||
.tooltip=${this._formatTotal(this._total)}
|
||||
>
|
||||
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
||||
</hui-energy-graph-chip>`
|
||||
: nothing}
|
||||
</div>
|
||||
<div
|
||||
class="content ${classMap({
|
||||
"has-header": !!this._config.title,
|
||||
|
||||
Reference in New Issue
Block a user