mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Add multiselect area to automation/scene/script (#20604)
This commit is contained in:
parent
7e9b01b56d
commit
87bcd3e471
@ -15,6 +15,7 @@ import {
|
|||||||
mdiPlus,
|
mdiPlus,
|
||||||
mdiRobotHappy,
|
mdiRobotHappy,
|
||||||
mdiTag,
|
mdiTag,
|
||||||
|
mdiTextureBox,
|
||||||
mdiToggleSwitch,
|
mdiToggleSwitch,
|
||||||
mdiToggleSwitchOffOutline,
|
mdiToggleSwitchOffOutline,
|
||||||
mdiTransitConnection,
|
mdiTransitConnection,
|
||||||
@ -69,6 +70,7 @@ import type { HaMenu } from "../../../components/ha-menu";
|
|||||||
import "../../../components/ha-menu-item";
|
import "../../../components/ha-menu-item";
|
||||||
import "../../../components/ha-sub-menu";
|
import "../../../components/ha-sub-menu";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
|
import { createAreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import {
|
import {
|
||||||
AutomationEntity,
|
AutomationEntity,
|
||||||
deleteAutomation,
|
deleteAutomation,
|
||||||
@ -106,6 +108,7 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import { HomeAssistant, Route, ServiceCallResponse } from "../../../types";
|
import { HomeAssistant, Route, ServiceCallResponse } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { turnOnOffEntity } from "../../lovelace/common/entity/turn-on-off-entity";
|
import { turnOnOffEntity } from "../../lovelace/common/entity/turn-on-off-entity";
|
||||||
|
import { showAreaRegistryDetailDialog } from "../areas/show-dialog-area-registry-detail";
|
||||||
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
@ -403,6 +406,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
|||||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||||
</div>
|
</div>
|
||||||
</ha-menu-item>`;
|
</ha-menu-item>`;
|
||||||
|
|
||||||
const labelItems = html`${this._labels?.map((label) => {
|
const labelItems = html`${this._labels?.map((label) => {
|
||||||
const color = label.color ? computeCssColor(label.color) : undefined;
|
const color = label.color ? computeCssColor(label.color) : undefined;
|
||||||
const selected = this._selected.every((entityId) =>
|
const selected = this._selected.every((entityId) =>
|
||||||
@ -440,10 +444,45 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
|||||||
</div></ha-menu-item
|
</div></ha-menu-item
|
||||||
>`;
|
>`;
|
||||||
|
|
||||||
const labelsInOverflow =
|
const areaItems = html`${Object.values(this.hass.areas).map(
|
||||||
(this._sizeController.value && this._sizeController.value < 700) ||
|
(area) =>
|
||||||
|
html`<ha-menu-item
|
||||||
|
.value=${area.area_id}
|
||||||
|
@click=${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-menu-item>`
|
||||||
|
)}
|
||||||
|
<ha-menu-item .value=${null} @click=${this._handleBulkArea}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>
|
||||||
|
<md-divider role="separator" tabindex="-1"></md-divider>
|
||||||
|
<ha-menu-item @click=${this._bulkCreateArea}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>`;
|
||||||
|
|
||||||
|
const areasInOverflow =
|
||||||
|
(this._sizeController.value && this._sizeController.value < 900) ||
|
||||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||||
|
|
||||||
|
const labelsInOverflow =
|
||||||
|
areasInOverflow &&
|
||||||
|
(!this._sizeController.value || this._sizeController.value < 700);
|
||||||
|
|
||||||
const automations = this._automations(
|
const automations = this._automations(
|
||||||
this.automations,
|
this.automations,
|
||||||
this._entityReg,
|
this._entityReg,
|
||||||
@ -598,6 +637,22 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
|||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
</ha-assist-chip>
|
</ha-assist-chip>
|
||||||
${labelItems}
|
${labelItems}
|
||||||
|
</ha-button-menu-new>`}
|
||||||
|
${areasInOverflow
|
||||||
|
? nothing
|
||||||
|
: html`<ha-button-menu-new 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-button-menu-new>`}`
|
</ha-button-menu-new>`}`
|
||||||
: nothing
|
: nothing
|
||||||
}
|
}
|
||||||
@ -662,6 +717,24 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
|||||||
</ha-sub-menu>`
|
</ha-sub-menu>`
|
||||||
: nothing
|
: nothing
|
||||||
}
|
}
|
||||||
|
${
|
||||||
|
this.narrow || areasInOverflow
|
||||||
|
? html`<ha-sub-menu>
|
||||||
|
<ha-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-menu-item>
|
||||||
|
<ha-menu slot="menu">${areaItems}</ha-menu>
|
||||||
|
</ha-sub-menu>`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
<ha-menu-item @click=${this._handleBulkEnable}>
|
<ha-menu-item @click=${this._handleBulkEnable}>
|
||||||
<ha-svg-icon slot="start" .path=${mdiToggleSwitch}></ha-svg-icon>
|
<ha-svg-icon slot="start" .path=${mdiToggleSwitch}></ha-svg-icon>
|
||||||
<div slot="headline">
|
<div slot="headline">
|
||||||
@ -1191,6 +1264,46 @@ ${rejected
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _handleBulkArea(ev) {
|
||||||
|
const area = ev.currentTarget.value;
|
||||||
|
this._bulkAddArea(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _bulkAddArea(area: string) {
|
||||||
|
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||||
|
this._selected.forEach((entityId) => {
|
||||||
|
promises.push(
|
||||||
|
updateEntityRegistryEntry(this.hass, entityId, {
|
||||||
|
area_id: area,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const result = await Promise.allSettled(promises);
|
||||||
|
if (hasRejectedItems(result)) {
|
||||||
|
const rejected = rejectedItems(result);
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize("ui.panel.config.common.multiselect.failed", {
|
||||||
|
number: rejected.length,
|
||||||
|
}),
|
||||||
|
text: html`<pre>
|
||||||
|
${rejected
|
||||||
|
.map((r) => r.reason.message || r.reason.code || r.reason)
|
||||||
|
.join("\r\n")}</pre
|
||||||
|
>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _bulkCreateArea() {
|
||||||
|
showAreaRegistryDetailDialog(this, {
|
||||||
|
createEntry: async (values) => {
|
||||||
|
const area = await createAreaRegistryEntry(this.hass, values);
|
||||||
|
this._bulkAddArea(area.area_id);
|
||||||
|
return area;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async _handleBulkEnable() {
|
private async _handleBulkEnable() {
|
||||||
const promises: Promise<ServiceCallResponse>[] = [];
|
const promises: Promise<ServiceCallResponse>[] = [];
|
||||||
this._selected.forEach((entityId) => {
|
this._selected.forEach((entityId) => {
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
mdiPlay,
|
mdiPlay,
|
||||||
mdiPlus,
|
mdiPlus,
|
||||||
mdiTag,
|
mdiTag,
|
||||||
|
mdiTextureBox,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { differenceInDays } from "date-fns";
|
import { differenceInDays } from "date-fns";
|
||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
@ -61,6 +62,7 @@ import "../../../components/ha-menu-item";
|
|||||||
import "../../../components/ha-state-icon";
|
import "../../../components/ha-state-icon";
|
||||||
import "../../../components/ha-sub-menu";
|
import "../../../components/ha-sub-menu";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
|
import { createAreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import {
|
import {
|
||||||
CategoryRegistryEntry,
|
CategoryRegistryEntry,
|
||||||
createCategoryRegistryEntry,
|
createCategoryRegistryEntry,
|
||||||
@ -97,6 +99,7 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
|
import { showAreaRegistryDetailDialog } from "../areas/show-dialog-area-registry-detail";
|
||||||
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
@ -406,6 +409,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
|||||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||||
</div>
|
</div>
|
||||||
</ha-menu-item>`;
|
</ha-menu-item>`;
|
||||||
|
|
||||||
const labelItems = html` ${this._labels?.map((label) => {
|
const labelItems = html` ${this._labels?.map((label) => {
|
||||||
const color = label.color ? computeCssColor(label.color) : undefined;
|
const color = label.color ? computeCssColor(label.color) : undefined;
|
||||||
const selected = this._selected.every((entityId) =>
|
const selected = this._selected.every((entityId) =>
|
||||||
@ -442,9 +446,46 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
|||||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||||
</div></ha-menu-item
|
</div></ha-menu-item
|
||||||
>`;
|
>`;
|
||||||
const labelsInOverflow =
|
|
||||||
(this._sizeController.value && this._sizeController.value < 700) ||
|
const areaItems = html`${Object.values(this.hass.areas).map(
|
||||||
|
(area) =>
|
||||||
|
html`<ha-menu-item
|
||||||
|
.value=${area.area_id}
|
||||||
|
@click=${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-menu-item>`
|
||||||
|
)}
|
||||||
|
<ha-menu-item .value=${null} @click=${this._handleBulkArea}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>
|
||||||
|
<md-divider role="separator" tabindex="-1"></md-divider>
|
||||||
|
<ha-menu-item @click=${this._bulkCreateArea}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>`;
|
||||||
|
|
||||||
|
const areasInOverflow =
|
||||||
|
(this._sizeController.value && this._sizeController.value < 900) ||
|
||||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||||
|
|
||||||
|
const labelsInOverflow =
|
||||||
|
areasInOverflow &&
|
||||||
|
(!this._sizeController.value || this._sizeController.value < 700);
|
||||||
|
|
||||||
const scenes = this._scenes(
|
const scenes = this._scenes(
|
||||||
this.scenes,
|
this.scenes,
|
||||||
this._entityReg,
|
this._entityReg,
|
||||||
@ -453,6 +494,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
|||||||
this._labels,
|
this._labels,
|
||||||
this._filteredScenes
|
this._filteredScenes
|
||||||
);
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage-data-table
|
<hass-tabs-subpage-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -582,9 +624,25 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
|||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
</ha-assist-chip>
|
</ha-assist-chip>
|
||||||
${labelItems}
|
${labelItems}
|
||||||
|
</ha-button-menu-new>`}
|
||||||
|
${areasInOverflow
|
||||||
|
? nothing
|
||||||
|
: html`<ha-button-menu-new 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-button-menu-new>`}`
|
</ha-button-menu-new>`}`
|
||||||
: nothing}
|
: nothing}
|
||||||
${this.narrow || labelsInOverflow
|
${this.narrow || areasInOverflow
|
||||||
? html`
|
? html`
|
||||||
<ha-button-menu-new has-overflow slot="selection-bar">
|
<ha-button-menu-new has-overflow slot="selection-bar">
|
||||||
${
|
${
|
||||||
@ -630,8 +688,8 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
|||||||
: nothing
|
: nothing
|
||||||
}
|
}
|
||||||
${
|
${
|
||||||
this.narrow || this.hass.dockedSidebar === "docked"
|
this.narrow || labelsInOverflow
|
||||||
? html` <ha-sub-menu>
|
? html`<ha-sub-menu>
|
||||||
<ha-menu-item slot="item">
|
<ha-menu-item slot="item">
|
||||||
<div slot="headline">
|
<div slot="headline">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -647,6 +705,24 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
|||||||
</ha-sub-menu>`
|
</ha-sub-menu>`
|
||||||
: nothing
|
: nothing
|
||||||
}
|
}
|
||||||
|
${
|
||||||
|
this.narrow || areasInOverflow
|
||||||
|
? html`<ha-sub-menu>
|
||||||
|
<ha-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-menu-item>
|
||||||
|
<ha-menu slot="menu">${areaItems}</ha-menu>
|
||||||
|
</ha-sub-menu>`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
</ha-button-menu-new>`
|
</ha-button-menu-new>`
|
||||||
: nothing}
|
: nothing}
|
||||||
${!this.scenes.length
|
${!this.scenes.length
|
||||||
@ -875,6 +951,46 @@ ${rejected
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _handleBulkArea(ev) {
|
||||||
|
const area = ev.currentTarget.value;
|
||||||
|
this._bulkAddArea(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _bulkAddArea(area: string) {
|
||||||
|
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||||
|
this._selected.forEach((entityId) => {
|
||||||
|
promises.push(
|
||||||
|
updateEntityRegistryEntry(this.hass, entityId, {
|
||||||
|
area_id: area,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const result = await Promise.allSettled(promises);
|
||||||
|
if (hasRejectedItems(result)) {
|
||||||
|
const rejected = rejectedItems(result);
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize("ui.panel.config.common.multiselect.failed", {
|
||||||
|
number: rejected.length,
|
||||||
|
}),
|
||||||
|
text: html`<pre>
|
||||||
|
${rejected
|
||||||
|
.map((r) => r.reason.message || r.reason.code || r.reason)
|
||||||
|
.join("\r\n")}</pre
|
||||||
|
>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _bulkCreateArea() {
|
||||||
|
showAreaRegistryDetailDialog(this, {
|
||||||
|
createEntry: async (values) => {
|
||||||
|
const area = await createAreaRegistryEntry(this.hass, values);
|
||||||
|
this._bulkAddArea(area.area_id);
|
||||||
|
return area;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private _editCategory(scene: any) {
|
private _editCategory(scene: any) {
|
||||||
const entityReg = this._entityReg.find(
|
const entityReg = this._entityReg.find(
|
||||||
(reg) => reg.entity_id === scene.entity_id
|
(reg) => reg.entity_id === scene.entity_id
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
mdiPlus,
|
mdiPlus,
|
||||||
mdiScriptText,
|
mdiScriptText,
|
||||||
mdiTag,
|
mdiTag,
|
||||||
|
mdiTextureBox,
|
||||||
mdiTransitConnection,
|
mdiTransitConnection,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { differenceInDays } from "date-fns";
|
import { differenceInDays } from "date-fns";
|
||||||
@ -61,6 +62,7 @@ import "../../../components/ha-icon-overflow-menu";
|
|||||||
import "../../../components/ha-menu-item";
|
import "../../../components/ha-menu-item";
|
||||||
import "../../../components/ha-sub-menu";
|
import "../../../components/ha-sub-menu";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
|
import { createAreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import {
|
import {
|
||||||
CategoryRegistryEntry,
|
CategoryRegistryEntry,
|
||||||
createCategoryRegistryEntry,
|
createCategoryRegistryEntry,
|
||||||
@ -98,6 +100,7 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
|
import { showAreaRegistryDetailDialog } from "../areas/show-dialog-area-registry-detail";
|
||||||
import { showNewAutomationDialog } from "../automation/show-dialog-new-automation";
|
import { showNewAutomationDialog } from "../automation/show-dialog-new-automation";
|
||||||
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||||
@ -418,6 +421,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
|||||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||||
</div>
|
</div>
|
||||||
</ha-menu-item>`;
|
</ha-menu-item>`;
|
||||||
|
|
||||||
const labelItems = html`${this._labels?.map((label) => {
|
const labelItems = html`${this._labels?.map((label) => {
|
||||||
const color = label.color ? computeCssColor(label.color) : undefined;
|
const color = label.color ? computeCssColor(label.color) : undefined;
|
||||||
const selected = this._selected.every((entityId) =>
|
const selected = this._selected.every((entityId) =>
|
||||||
@ -454,9 +458,46 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
|||||||
${this.hass.localize("ui.panel.config.labels.add_label")}
|
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||||
</div></ha-menu-item
|
</div></ha-menu-item
|
||||||
>`;
|
>`;
|
||||||
const labelsInOverflow =
|
|
||||||
(this._sizeController.value && this._sizeController.value < 700) ||
|
const areaItems = html`${Object.values(this.hass.areas).map(
|
||||||
|
(area) =>
|
||||||
|
html`<ha-menu-item
|
||||||
|
.value=${area.area_id}
|
||||||
|
@click=${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-menu-item>`
|
||||||
|
)}
|
||||||
|
<ha-menu-item .value=${null} @click=${this._handleBulkArea}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.devices.picker.bulk_actions.no_area"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>
|
||||||
|
<md-divider role="separator" tabindex="-1"></md-divider>
|
||||||
|
<ha-menu-item @click=${this._bulkCreateArea}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.devices.picker.bulk_actions.add_area"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>`;
|
||||||
|
|
||||||
|
const areasInOverflow =
|
||||||
|
(this._sizeController.value && this._sizeController.value < 900) ||
|
||||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||||
|
|
||||||
|
const labelsInOverflow =
|
||||||
|
areasInOverflow &&
|
||||||
|
(!this._sizeController.value || this._sizeController.value < 700);
|
||||||
|
|
||||||
const scripts = this._scripts(
|
const scripts = this._scripts(
|
||||||
this.scripts,
|
this.scripts,
|
||||||
this._entityReg,
|
this._entityReg,
|
||||||
@ -608,9 +649,25 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
|||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
</ha-assist-chip>
|
</ha-assist-chip>
|
||||||
${labelItems}
|
${labelItems}
|
||||||
|
</ha-button-menu-new>`}
|
||||||
|
${areasInOverflow
|
||||||
|
? nothing
|
||||||
|
: html`<ha-button-menu-new 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-button-menu-new>`}`
|
</ha-button-menu-new>`}`
|
||||||
: nothing}
|
: nothing}
|
||||||
${this.narrow || labelsInOverflow
|
${this.narrow || areasInOverflow
|
||||||
? html`
|
? html`
|
||||||
<ha-button-menu-new has-overflow slot="selection-bar">
|
<ha-button-menu-new has-overflow slot="selection-bar">
|
||||||
${
|
${
|
||||||
@ -656,8 +713,8 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
|||||||
: nothing
|
: nothing
|
||||||
}
|
}
|
||||||
${
|
${
|
||||||
this.narrow || this.hass.dockedSidebar === "docked"
|
this.narrow || labelsInOverflow
|
||||||
? html` <ha-sub-menu>
|
? html`<ha-sub-menu>
|
||||||
<ha-menu-item slot="item">
|
<ha-menu-item slot="item">
|
||||||
<div slot="headline">
|
<div slot="headline">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -673,6 +730,24 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
|||||||
</ha-sub-menu>`
|
</ha-sub-menu>`
|
||||||
: nothing
|
: nothing
|
||||||
}
|
}
|
||||||
|
${
|
||||||
|
this.narrow || areasInOverflow
|
||||||
|
? html`<ha-sub-menu>
|
||||||
|
<ha-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-menu-item>
|
||||||
|
<ha-menu slot="menu">${areaItems}</ha-menu>
|
||||||
|
</ha-sub-menu>`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
</ha-button-menu-new>`
|
</ha-button-menu-new>`
|
||||||
: nothing}
|
: nothing}
|
||||||
${!this.scripts.length
|
${!this.scripts.length
|
||||||
@ -1111,6 +1186,46 @@ ${rejected
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _handleBulkArea(ev) {
|
||||||
|
const area = ev.currentTarget.value;
|
||||||
|
this._bulkAddArea(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _bulkAddArea(area: string) {
|
||||||
|
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||||
|
this._selected.forEach((entityId) => {
|
||||||
|
promises.push(
|
||||||
|
updateEntityRegistryEntry(this.hass, entityId, {
|
||||||
|
area_id: area,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const result = await Promise.allSettled(promises);
|
||||||
|
if (hasRejectedItems(result)) {
|
||||||
|
const rejected = rejectedItems(result);
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize("ui.panel.config.common.multiselect.failed", {
|
||||||
|
number: rejected.length,
|
||||||
|
}),
|
||||||
|
text: html`<pre>
|
||||||
|
${rejected
|
||||||
|
.map((r) => r.reason.message || r.reason.code || r.reason)
|
||||||
|
.join("\r\n")}</pre
|
||||||
|
>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _bulkCreateArea() {
|
||||||
|
showAreaRegistryDetailDialog(this, {
|
||||||
|
createEntry: async (values) => {
|
||||||
|
const area = await createAreaRegistryEntry(this.hass, values);
|
||||||
|
this._bulkAddArea(area.area_id);
|
||||||
|
return area;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private _handleSortingChanged(ev: CustomEvent) {
|
private _handleSortingChanged(ev: CustomEvent) {
|
||||||
this._activeSorting = ev.detail;
|
this._activeSorting = ev.detail;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user