mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 03:06:41 +00:00
Add category and filters to helpers (#20346)
* Add category and filters to helpers * Add support for adding label and category in multi select * remove labels multi
This commit is contained in:
parent
578d3c4260
commit
ccde9cceee
@ -28,6 +28,7 @@ export type ItemType =
|
|||||||
| "entity"
|
| "entity"
|
||||||
| "floor"
|
| "floor"
|
||||||
| "group"
|
| "group"
|
||||||
|
| "label"
|
||||||
| "scene"
|
| "scene"
|
||||||
| "script"
|
| "script"
|
||||||
| "automation_blueprint"
|
| "automation_blueprint"
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
|
import { consume } from "@lit-labs/context";
|
||||||
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
||||||
import { mdiAlertCircle, mdiPencilOff, mdiPlus } from "@mdi/js";
|
import {
|
||||||
|
mdiAlertCircle,
|
||||||
|
mdiChevronRight,
|
||||||
|
mdiCog,
|
||||||
|
mdiDotsVertical,
|
||||||
|
mdiMenuDown,
|
||||||
|
mdiPencilOff,
|
||||||
|
mdiPlus,
|
||||||
|
mdiTag,
|
||||||
|
} from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -11,8 +21,9 @@ import {
|
|||||||
nothing,
|
nothing,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { consume } from "@lit-labs/context";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { computeCssColor } from "../../../common/color/compute-color";
|
||||||
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import {
|
import {
|
||||||
@ -23,22 +34,42 @@ import { extractSearchParam } from "../../../common/url/search-params";
|
|||||||
import {
|
import {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
|
SelectionChangedEvent,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
import "../../../components/data-table/ha-data-table-labels";
|
import "../../../components/data-table/ha-data-table-labels";
|
||||||
import "../../../components/ha-fab";
|
import "../../../components/ha-fab";
|
||||||
|
import "../../../components/ha-filter-categories";
|
||||||
|
import "../../../components/ha-filter-devices";
|
||||||
|
import "../../../components/ha-filter-entities";
|
||||||
|
import "../../../components/ha-filter-floor-areas";
|
||||||
|
import "../../../components/ha-filter-labels";
|
||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
|
import "../../../components/ha-icon-overflow-menu";
|
||||||
import "../../../components/ha-state-icon";
|
import "../../../components/ha-state-icon";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
|
import {
|
||||||
|
CategoryRegistryEntry,
|
||||||
|
createCategoryRegistryEntry,
|
||||||
|
subscribeCategoryRegistry,
|
||||||
|
} from "../../../data/category_registry";
|
||||||
import {
|
import {
|
||||||
ConfigEntry,
|
ConfigEntry,
|
||||||
subscribeConfigEntries,
|
subscribeConfigEntries,
|
||||||
} from "../../../data/config_entries";
|
} from "../../../data/config_entries";
|
||||||
import { getConfigFlowHandlers } from "../../../data/config_flow";
|
import { getConfigFlowHandlers } from "../../../data/config_flow";
|
||||||
|
import { fullEntitiesContext } from "../../../data/context";
|
||||||
import {
|
import {
|
||||||
EntityRegistryEntry,
|
EntityRegistryEntry,
|
||||||
|
UpdateEntityRegistryEntryResult,
|
||||||
subscribeEntityRegistry,
|
subscribeEntityRegistry,
|
||||||
|
updateEntityRegistryEntry,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import { domainToName } from "../../../data/integration";
|
import { domainToName } from "../../../data/integration";
|
||||||
|
import {
|
||||||
|
LabelRegistryEntry,
|
||||||
|
createLabelRegistryEntry,
|
||||||
|
subscribeLabelRegistry,
|
||||||
|
} from "../../../data/label_registry";
|
||||||
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
|
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
|
||||||
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
||||||
import {
|
import {
|
||||||
@ -49,18 +80,15 @@ import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info
|
|||||||
import "../../../layouts/hass-loading-screen";
|
import "../../../layouts/hass-loading-screen";
|
||||||
import "../../../layouts/hass-tabs-subpage-data-table";
|
import "../../../layouts/hass-tabs-subpage-data-table";
|
||||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||||
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
|
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "../integrations/ha-integration-overflow-menu";
|
import "../integrations/ha-integration-overflow-menu";
|
||||||
import { isHelperDomain } from "./const";
|
import { isHelperDomain } from "./const";
|
||||||
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
||||||
import {
|
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||||
LabelRegistryEntry,
|
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||||
subscribeLabelRegistry,
|
|
||||||
} from "../../../data/label_registry";
|
|
||||||
import { fullEntitiesContext } from "../../../data/context";
|
|
||||||
import "../../../components/ha-filter-labels";
|
|
||||||
import { haStyle } from "../../../resources/styles";
|
|
||||||
|
|
||||||
type HelperItem = {
|
type HelperItem = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -71,6 +99,7 @@ type HelperItem = {
|
|||||||
type: string;
|
type: string;
|
||||||
configEntry?: ConfigEntry;
|
configEntry?: ConfigEntry;
|
||||||
entity?: HassEntity;
|
entity?: HassEntity;
|
||||||
|
category: string | undefined;
|
||||||
label_entries: LabelRegistryEntry[];
|
label_entries: LabelRegistryEntry[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,6 +140,8 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _configEntries?: Record<string, ConfigEntry>;
|
@state() private _configEntries?: Record<string, ConfigEntry>;
|
||||||
|
|
||||||
|
@state() private _selected: string[] = [];
|
||||||
|
|
||||||
@state() private _activeFilters?: string[];
|
@state() private _activeFilters?: string[];
|
||||||
|
|
||||||
@state() private _filters: Record<
|
@state() private _filters: Record<
|
||||||
@ -120,6 +151,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _expandedFilter?: string;
|
@state() private _expandedFilter?: string;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_categories!: CategoryRegistryEntry[];
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
_labels!: LabelRegistryEntry[];
|
_labels!: LabelRegistryEntry[];
|
||||||
|
|
||||||
@ -156,65 +190,86 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
subscribeLabelRegistry(this.hass.connection, (labels) => {
|
subscribeLabelRegistry(this.hass.connection, (labels) => {
|
||||||
this._labels = labels;
|
this._labels = labels;
|
||||||
}),
|
}),
|
||||||
|
subscribeCategoryRegistry(
|
||||||
|
this.hass.connection,
|
||||||
|
"helpers",
|
||||||
|
(categories) => {
|
||||||
|
this._categories = categories;
|
||||||
|
}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean, localize: LocalizeFunc): DataTableColumnContainer => {
|
(
|
||||||
const columns: DataTableColumnContainer<HelperItem> = {
|
narrow: boolean,
|
||||||
icon: {
|
localize: LocalizeFunc
|
||||||
title: "",
|
): DataTableColumnContainer<HelperItem> => ({
|
||||||
label: localize("ui.panel.config.helpers.picker.headers.icon"),
|
icon: {
|
||||||
type: "icon",
|
title: "",
|
||||||
template: (helper) =>
|
label: localize("ui.panel.config.helpers.picker.headers.icon"),
|
||||||
helper.entity
|
type: "icon",
|
||||||
? html`<ha-state-icon
|
template: (helper) =>
|
||||||
.hass=${this.hass}
|
helper.entity
|
||||||
.stateObj=${helper.entity}
|
? html`<ha-state-icon
|
||||||
></ha-state-icon>`
|
.hass=${this.hass}
|
||||||
: html`<ha-svg-icon
|
.stateObj=${helper.entity}
|
||||||
.path=${helper.icon}
|
></ha-state-icon>`
|
||||||
style="color: var(--error-color)"
|
: html`<ha-svg-icon
|
||||||
></ha-svg-icon>`,
|
.path=${helper.icon}
|
||||||
},
|
style="color: var(--error-color)"
|
||||||
name: {
|
></ha-svg-icon>`,
|
||||||
title: localize("ui.panel.config.helpers.picker.headers.name"),
|
},
|
||||||
main: true,
|
name: {
|
||||||
sortable: true,
|
title: localize("ui.panel.config.helpers.picker.headers.name"),
|
||||||
filterable: true,
|
main: true,
|
||||||
grows: true,
|
sortable: true,
|
||||||
direction: "asc",
|
filterable: true,
|
||||||
template: (helper) => html`
|
grows: true,
|
||||||
<div style="font-size: 14px;">${helper.name}</div>
|
direction: "asc",
|
||||||
${narrow
|
template: (helper) => html`
|
||||||
? html`<div class="secondary">${helper.entity_id}</div> `
|
<div style="font-size: 14px;">${helper.name}</div>
|
||||||
: nothing}
|
${narrow
|
||||||
${helper.label_entries.length
|
? html`<div class="secondary">${helper.entity_id}</div> `
|
||||||
? html`
|
: nothing}
|
||||||
<ha-data-table-labels
|
${helper.label_entries.length
|
||||||
.labels=${helper.label_entries}
|
? html`
|
||||||
></ha-data-table-labels>
|
<ha-data-table-labels
|
||||||
`
|
.labels=${helper.label_entries}
|
||||||
: nothing}
|
></ha-data-table-labels>
|
||||||
`,
|
`
|
||||||
},
|
: nothing}
|
||||||
};
|
`,
|
||||||
if (!narrow) {
|
},
|
||||||
columns.entity_id = {
|
entity_id: {
|
||||||
title: localize("ui.panel.config.helpers.picker.headers.entity_id"),
|
title: localize("ui.panel.config.helpers.picker.headers.entity_id"),
|
||||||
sortable: true,
|
hidden: this.narrow,
|
||||||
filterable: true,
|
sortable: true,
|
||||||
width: "25%",
|
filterable: true,
|
||||||
};
|
width: "25%",
|
||||||
}
|
},
|
||||||
columns.localized_type = {
|
category: {
|
||||||
|
title: localize("ui.panel.config.helpers.picker.headers.category"),
|
||||||
|
hidden: true,
|
||||||
|
groupable: true,
|
||||||
|
filterable: true,
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
title: "",
|
||||||
|
hidden: true,
|
||||||
|
filterable: true,
|
||||||
|
template: (helper) =>
|
||||||
|
helper.label_entries.map((lbl) => lbl.name).join(" "),
|
||||||
|
},
|
||||||
|
localized_type: {
|
||||||
title: localize("ui.panel.config.helpers.picker.headers.type"),
|
title: localize("ui.panel.config.helpers.picker.headers.type"),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
width: "25%",
|
width: "25%",
|
||||||
filterable: true,
|
filterable: true,
|
||||||
groupable: true,
|
groupable: true,
|
||||||
};
|
},
|
||||||
columns.editable = {
|
editable: {
|
||||||
title: "",
|
title: "",
|
||||||
label: this.hass.localize(
|
label: this.hass.localize(
|
||||||
"ui.panel.config.helpers.picker.headers.editable"
|
"ui.panel.config.helpers.picker.headers.editable"
|
||||||
@ -237,9 +292,36 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
`,
|
`,
|
||||||
};
|
},
|
||||||
return columns;
|
actions: {
|
||||||
}
|
title: "",
|
||||||
|
width: "64px",
|
||||||
|
type: "overflow-menu",
|
||||||
|
template: (helper) => html`
|
||||||
|
<ha-icon-overflow-menu
|
||||||
|
.hass=${this.hass}
|
||||||
|
narrow
|
||||||
|
.items=${[
|
||||||
|
{
|
||||||
|
path: mdiCog,
|
||||||
|
label: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.picker.show_settings"
|
||||||
|
),
|
||||||
|
action: () => this._openSettings(helper),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: mdiTag,
|
||||||
|
label: this.hass.localize(
|
||||||
|
`ui.panel.config.automation.picker.${helper.category ? "edit_category" : "assign_category"}`
|
||||||
|
),
|
||||||
|
action: () => this._editCategory(helper),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
</ha-icon-overflow-menu>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
private _getItems = memoizeOne(
|
private _getItems = memoizeOne(
|
||||||
@ -249,6 +331,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
entityEntries: Record<string, EntityRegistryEntry>,
|
entityEntries: Record<string, EntityRegistryEntry>,
|
||||||
configEntries: Record<string, ConfigEntry>,
|
configEntries: Record<string, ConfigEntry>,
|
||||||
entityReg: EntityRegistryEntry[],
|
entityReg: EntityRegistryEntry[],
|
||||||
|
categoryReg?: CategoryRegistryEntry[],
|
||||||
labelReg?: LabelRegistryEntry[],
|
labelReg?: LabelRegistryEntry[],
|
||||||
filteredStateItems?: string[] | null
|
filteredStateItems?: string[] | null
|
||||||
): HelperItem[] => {
|
): HelperItem[] => {
|
||||||
@ -305,6 +388,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
(reg) => reg.entity_id === item.entity_id
|
(reg) => reg.entity_id === item.entity_id
|
||||||
);
|
);
|
||||||
const labels = labelReg && entityRegEntry?.labels;
|
const labels = labelReg && entityRegEntry?.labels;
|
||||||
|
const category = entityRegEntry?.categories.helpers;
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
localized_type: item.configEntry
|
localized_type: item.configEntry
|
||||||
@ -315,6 +399,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
label_entries: (labels || []).map(
|
label_entries: (labels || []).map(
|
||||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||||
),
|
),
|
||||||
|
category: category
|
||||||
|
? categoryReg?.find((cat) => cat.category_id === category)?.name
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -330,6 +417,66 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
return html` <hass-loading-screen></hass-loading-screen> `;
|
return html` <hass-loading-screen></hass-loading-screen> `;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const categoryItems = html`${this._categories?.map(
|
||||||
|
(category) =>
|
||||||
|
html`<ha-menu-item
|
||||||
|
.value=${category.category_id}
|
||||||
|
@click=${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-menu-item>`
|
||||||
|
)}
|
||||||
|
<ha-menu-item .value=${null} @click=${this._handleBulkCategory}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.picker.bulk_actions.no_category"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>
|
||||||
|
<md-divider role="separator" tabindex="-1"></md-divider>
|
||||||
|
<ha-menu-item @click=${this._createCategory}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||||
|
</div>
|
||||||
|
</ha-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)
|
||||||
|
);
|
||||||
|
const partial =
|
||||||
|
!selected &&
|
||||||
|
this._selected.some((entityId) =>
|
||||||
|
this.hass.entities[entityId]?.labels.includes(label.label_id)
|
||||||
|
);
|
||||||
|
return html`<ha-menu-item
|
||||||
|
.value=${label.label_id}
|
||||||
|
.action=${selected ? "remove" : "add"}
|
||||||
|
@click=${this._handleBulkLabel}
|
||||||
|
>
|
||||||
|
<ha-checkbox
|
||||||
|
slot="start"
|
||||||
|
.checked=${selected}
|
||||||
|
.indeterminate=${partial}
|
||||||
|
reducedTouchTarget
|
||||||
|
></ha-checkbox>
|
||||||
|
<ha-label style=${color ? `--color: ${color}` : ""}>
|
||||||
|
${label.icon
|
||||||
|
? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>`
|
||||||
|
: nothing}
|
||||||
|
${label.name}
|
||||||
|
</ha-label>
|
||||||
|
</ha-menu-item> `;
|
||||||
|
})}<md-divider role="separator" tabindex="-1"></md-divider>
|
||||||
|
<ha-menu-item @click=${this._createLabel}>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||||
|
</div>
|
||||||
|
</ha-menu-item>`;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage-data-table
|
<hass-tabs-subpage-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -337,6 +484,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
back-path="/config"
|
back-path="/config"
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${configSections.devices}
|
.tabs=${configSections.devices}
|
||||||
|
selectable
|
||||||
|
.selected=${this._selected.length}
|
||||||
|
@selection-changed=${this._handleSelectionChanged}
|
||||||
hasFilters
|
hasFilters
|
||||||
.filters=${Object.values(this._filters).filter(
|
.filters=${Object.values(this._filters).filter(
|
||||||
(filter) => filter.value?.length
|
(filter) => filter.value?.length
|
||||||
@ -348,9 +498,11 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
this._entityEntries,
|
this._entityEntries,
|
||||||
this._configEntries,
|
this._configEntries,
|
||||||
this._entityReg,
|
this._entityReg,
|
||||||
|
this._categories,
|
||||||
this._labels,
|
this._labels,
|
||||||
this._filteredStateItems
|
this._filteredStateItems
|
||||||
)}
|
)}
|
||||||
|
initialGroupColumn="category"
|
||||||
.activeFilters=${this._activeFilters}
|
.activeFilters=${this._activeFilters}
|
||||||
@clear-filter=${this._clearFilter}
|
@clear-filter=${this._clearFilter}
|
||||||
@row-click=${this._openEditDialog}
|
@row-click=${this._openEditDialog}
|
||||||
@ -361,6 +513,26 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
)}
|
)}
|
||||||
class=${this.narrow ? "narrow" : ""}
|
class=${this.narrow ? "narrow" : ""}
|
||||||
>
|
>
|
||||||
|
<ha-filter-floor-areas
|
||||||
|
.hass=${this.hass}
|
||||||
|
.type=${"entity"}
|
||||||
|
.value=${this._filters["ha-filter-floor-areas"]?.value}
|
||||||
|
@data-table-filter-changed=${this._filterChanged}
|
||||||
|
slot="filter-pane"
|
||||||
|
.expanded=${this._expandedFilter === "ha-filter-floor-areas"}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
@expanded-changed=${this._filterExpanded}
|
||||||
|
></ha-filter-floor-areas>
|
||||||
|
<ha-filter-devices
|
||||||
|
.hass=${this.hass}
|
||||||
|
.type=${"entity"}
|
||||||
|
.value=${this._filters["ha-filter-devices"]?.value}
|
||||||
|
@data-table-filter-changed=${this._filterChanged}
|
||||||
|
slot="filter-pane"
|
||||||
|
.expanded=${this._expandedFilter === "ha-filter-devices"}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
@expanded-changed=${this._filterExpanded}
|
||||||
|
></ha-filter-devices>
|
||||||
<ha-filter-labels
|
<ha-filter-labels
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.value=${this._filters["ha-filter-labels"]?.value}
|
.value=${this._filters["ha-filter-labels"]?.value}
|
||||||
@ -370,6 +542,114 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
@expanded-changed=${this._filterExpanded}
|
@expanded-changed=${this._filterExpanded}
|
||||||
></ha-filter-labels>
|
></ha-filter-labels>
|
||||||
|
<ha-filter-categories
|
||||||
|
.hass=${this.hass}
|
||||||
|
scope="helpers"
|
||||||
|
.value=${this._filters["ha-filter-categories"]?.value}
|
||||||
|
@data-table-filter-changed=${this._filterChanged}
|
||||||
|
slot="filter-pane"
|
||||||
|
.expanded=${this._expandedFilter === "ha-filter-categories"}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
@expanded-changed=${this._filterExpanded}
|
||||||
|
></ha-filter-categories>
|
||||||
|
|
||||||
|
${!this.narrow
|
||||||
|
? html`<ha-button-menu-new slot="selection-bar">
|
||||||
|
<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>
|
||||||
|
${categoryItems}
|
||||||
|
</ha-button-menu-new>
|
||||||
|
${this.hass.dockedSidebar === "docked"
|
||||||
|
? nothing
|
||||||
|
: html`<ha-button-menu-new 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-button-menu-new>`}`
|
||||||
|
: nothing}
|
||||||
|
${this.narrow || this.hass.dockedSidebar === "docked"
|
||||||
|
? html`
|
||||||
|
<ha-button-menu-new 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=${"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-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-menu-item>
|
||||||
|
<ha-menu slot="menu">${categoryItems}</ha-menu>
|
||||||
|
</ha-sub-menu>`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
|
${
|
||||||
|
this.narrow || this.hass.dockedSidebar === "docked"
|
||||||
|
? html` <ha-sub-menu>
|
||||||
|
<ha-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-menu-item>
|
||||||
|
<ha-menu slot="menu">${labelItems}</ha-menu>
|
||||||
|
</ha-sub-menu>`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
|
</ha-button-menu-new>`
|
||||||
|
: nothing}
|
||||||
|
|
||||||
<ha-integration-overflow-menu
|
<ha-integration-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -437,6 +717,27 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
items.intersection(labelItems)
|
items.intersection(labelItems)
|
||||||
: new Set([...items].filter((x) => labelItems!.has(x)));
|
: new Set([...items].filter((x) => labelItems!.has(x)));
|
||||||
}
|
}
|
||||||
|
if (key === "ha-filter-categories" && filter.value?.length) {
|
||||||
|
const categoryItems: Set<string> = new Set();
|
||||||
|
this._stateItems
|
||||||
|
.filter(
|
||||||
|
(stateItem) =>
|
||||||
|
filter.value![0] ===
|
||||||
|
this._entityReg.find(
|
||||||
|
(reg) => reg.entity_id === stateItem.entity_id
|
||||||
|
)?.categories.helpers
|
||||||
|
)
|
||||||
|
.forEach((stateItem) => categoryItems.add(stateItem.entity_id));
|
||||||
|
if (!items) {
|
||||||
|
items = categoryItems;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
items =
|
||||||
|
"intersection" in items
|
||||||
|
? // @ts-ignore
|
||||||
|
items.intersection(categoryItems)
|
||||||
|
: new Set([...items].filter((x) => categoryItems!.has(x)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this._filteredStateItems = items ? [...items] : undefined;
|
this._filteredStateItems = items ? [...items] : undefined;
|
||||||
}
|
}
|
||||||
@ -446,6 +747,65 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
this._applyFilters();
|
this._applyFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _editCategory(helper: any) {
|
||||||
|
const entityReg = this._entityReg.find(
|
||||||
|
(reg) => reg.entity_id === helper.entity_id
|
||||||
|
);
|
||||||
|
if (!entityReg) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.picker.no_category_support"
|
||||||
|
),
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.automation.picker.no_category_entity_reg"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showAssignCategoryDialog(this, {
|
||||||
|
scope: "helpers",
|
||||||
|
entityReg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _handleBulkCategory(ev) {
|
||||||
|
const category = ev.currentTarget.value;
|
||||||
|
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||||
|
this._selected.forEach((entityId) => {
|
||||||
|
promises.push(
|
||||||
|
updateEntityRegistryEntry(this.hass, entityId, {
|
||||||
|
categories: { helpers: category },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _handleBulkLabel(ev) {
|
||||||
|
const label = ev.currentTarget.value;
|
||||||
|
const action = ev.currentTarget.action;
|
||||||
|
const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
|
||||||
|
this._selected.forEach((entityId) => {
|
||||||
|
promises.push(
|
||||||
|
updateEntityRegistryEntry(this.hass, entityId, {
|
||||||
|
labels:
|
||||||
|
action === "add"
|
||||||
|
? this.hass.entities[entityId].labels.concat(label)
|
||||||
|
: this.hass.entities[entityId].labels.filter(
|
||||||
|
(lbl) => lbl !== label
|
||||||
|
),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleSelectionChanged(
|
||||||
|
ev: HASSDomEvent<SelectionChangedEvent>
|
||||||
|
): void {
|
||||||
|
this._selected = ev.detail.value;
|
||||||
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
if (this.route.path === "/add") {
|
if (this.route.path === "/add") {
|
||||||
@ -563,10 +923,35 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _openSettings(helper: HelperItem) {
|
||||||
|
if (helper.entity) {
|
||||||
|
showMoreInfoDialog(this, {
|
||||||
|
entityId: helper.entity_id,
|
||||||
|
view: "settings",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showOptionsFlowDialog(this, helper.configEntry!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _createHelper() {
|
private _createHelper() {
|
||||||
showHelperDetailDialog(this, {});
|
showHelperDetailDialog(this, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _createCategory() {
|
||||||
|
showCategoryRegistryDetailDialog(this, {
|
||||||
|
scope: "helpers",
|
||||||
|
createEntry: (values) =>
|
||||||
|
createCategoryRegistryEntry(this.hass, "helpers", values),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createLabel() {
|
||||||
|
showLabelDetailDialog(this, {
|
||||||
|
createEntry: (values) => createLabelRegistryEntry(this.hass, values),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
@ -577,6 +962,16 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
hass-tabs-subpage-data-table.narrow {
|
hass-tabs-subpage-data-table.narrow {
|
||||||
--data-table-row-height: 72px;
|
--data-table-row-height: 72px;
|
||||||
}
|
}
|
||||||
|
ha-assist-chip {
|
||||||
|
--ha-assist-chip-container-shape: 10px;
|
||||||
|
}
|
||||||
|
ha-button-menu-new ha-assist-chip {
|
||||||
|
--md-assist-chip-trailing-space: 8px;
|
||||||
|
}
|
||||||
|
ha-label {
|
||||||
|
--ha-label-background-color: var(--color, var(--grey-color));
|
||||||
|
--ha-label-background-opacity: 0.5;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -2263,7 +2263,8 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"entity_id": "Entity ID",
|
"entity_id": "Entity ID",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"editable": "Editable"
|
"editable": "Editable",
|
||||||
|
"category": "Category"
|
||||||
},
|
},
|
||||||
"create_helper": "Create helper",
|
"create_helper": "Create helper",
|
||||||
"no_helpers": "Looks like you don't have any helpers yet!"
|
"no_helpers": "Looks like you don't have any helpers yet!"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user