filter.value?.length
+ ).length}
+ .columns=${this._columns(
+ this.narrow,
+ this.hass.localize,
+ this.hass.locale
+ )}
+ .data=${this._scripts(
+ this.scripts,
+ this._entityReg,
+ this._categories,
+ this._labels,
+ this._filteredScripts
+ )}
.empty=${!this.scripts.length}
.activeFilters=${this._activeFilters}
id="entity_id"
@@ -255,6 +363,7 @@ class HaScriptPicker extends LitElement {
@clear-filter=${this._clearFilter}
hasFab
clickable
+ class=${this.narrow ? "narrow" : ""}
@row-click=${this._handleRowClicked}
>
+
+
+
+
+
+
${!this.scripts.length
? html`
@@ -303,6 +471,95 @@ class HaScriptPicker extends LitElement {
`;
}
+ private _filterExpanded(ev) {
+ if (ev.detail.expanded) {
+ this._expandedFilter = ev.target.localName;
+ } else if (this._expandedFilter === ev.target.localName) {
+ this._expandedFilter = undefined;
+ }
+ }
+
+ private _labelClicked = (ev: CustomEvent) => {
+ const label = ev.detail.label;
+ this._filters = {
+ ...this._filters,
+ "ha-filter-labels": {
+ value: [label.label_id],
+ items: undefined,
+ },
+ };
+ this._applyFilters();
+ };
+
+ private _filterChanged(ev) {
+ const type = ev.target.localName;
+ this._filters[type] = ev.detail;
+ this._applyFilters();
+ }
+
+ private _clearFilter() {
+ this._filters = {};
+ this._applyFilters();
+ }
+
+ private _applyFilters() {
+ const filters = Object.entries(this._filters);
+ let items: Set | undefined;
+ for (const [key, filter] of filters) {
+ if (filter.items) {
+ if (!items) {
+ items = filter.items;
+ continue;
+ }
+ items =
+ "intersection" in items
+ ? // @ts-ignore
+ items.intersection(filter.items)
+ : new Set([...items].filter((x) => filter.items!.has(x)));
+ }
+ if (key === "ha-filter-categories" && filter.value?.length) {
+ const categoryItems: Set = new Set();
+ this.scripts
+ .filter(
+ (script) =>
+ filter.value![0] ===
+ this._entityReg.find((reg) => reg.entity_id === script.entity_id)
+ ?.categories.script
+ )
+ .forEach((script) => categoryItems.add(script.entity_id));
+ if (!items) {
+ items = categoryItems;
+ continue;
+ }
+ items =
+ "intersection" in items
+ ? // @ts-ignore
+ items.intersection(categoryItems)
+ : new Set([...items].filter((x) => categoryItems!.has(x)));
+ }
+ if (key === "ha-filter-labels" && filter.value?.length) {
+ const labelItems: Set = new Set();
+ this.scripts
+ .filter((script) =>
+ this._entityReg
+ .find((reg) => reg.entity_id === script.entity_id)
+ ?.labels.some((lbl) => filter.value!.includes(lbl))
+ )
+ .forEach((script) => labelItems.add(script.entity_id));
+ if (!items) {
+ items = labelItems;
+ continue;
+ }
+ items =
+ "intersection" in items
+ ? // @ts-ignore
+ items.intersection(labelItems)
+ : new Set([...items].filter((x) => labelItems!.has(x)));
+ }
+ }
+ this._filteredScripts = items ? [...items] : undefined;
+ }
+
firstUpdated() {
if (this._searchParms.has("blueprint")) {
this._filterBlueprint();
@@ -314,28 +571,36 @@ class HaScriptPicker extends LitElement {
if (!blueprint) {
return;
}
- const [related, blueprints] = await Promise.all([
- findRelated(this.hass, "script_blueprint", blueprint),
- fetchBlueprints(this.hass, "script"),
- ]);
- this._filteredScripts = related.script || [];
- const blueprintMeta = blueprints[blueprint];
- this._activeFilters = [
- this.hass.localize(
- "ui.panel.config.script.picker.filtered_by_blueprint",
- {
- name:
- !blueprintMeta || "error" in blueprintMeta
- ? blueprint
- : blueprintMeta.metadata.name || blueprint,
- }
- ),
- ];
+ const related = await findRelated(this.hass, "script_blueprint", blueprint);
+ this._filters = {
+ ...this._filters,
+ "ha-filter-blueprints": {
+ value: [blueprint],
+ items: new Set(related.automation || []),
+ },
+ };
+ this._applyFilters();
}
- private _clearFilter() {
- this._filteredScripts = undefined;
- this._activeFilters = undefined;
+ private _editCategory(script: any) {
+ const entityReg = this._entityReg.find(
+ (reg) => reg.entity_id === script.entity_id
+ );
+ if (!entityReg) {
+ showAlertDialog(this, {
+ title: this.hass.localize(
+ "ui.panel.config.script.picker.no_category_support"
+ ),
+ text: this.hass.localize(
+ "ui.panel.config.script.picker.no_category_entity_reg"
+ ),
+ });
+ return;
+ }
+ showAssignCategoryDialog(this, {
+ scope: "script",
+ entityReg,
+ });
}
private _handleRowClicked(ev: HASSDomEvent) {
@@ -477,6 +742,12 @@ class HaScriptPicker extends LitElement {
return [
haStyle,
css`
+ hass-tabs-subpage-data-table {
+ --data-table-row-height: 60px;
+ }
+ hass-tabs-subpage-data-table.narrow {
+ --data-table-row-height: 72px;
+ }
a {
text-decoration: none;
}
diff --git a/src/translations/en.json b/src/translations/en.json
index 4a2a7b45fd..d1a4b1a6fb 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -3551,8 +3551,13 @@
"filtered_by_blueprint": "[%key:ui::panel::config::automation::picker::filtered_by_blueprint%]",
"headers": {
"name": "Name",
- "state": "State"
+ "state": "State",
+ "category": "Category"
},
+ "edit_category": "[%key:ui::panel::config::automation::picker::edit_category%]",
+ "assign_category": "[%key:ui::panel::config::automation::picker::assign_category%]",
+ "no_category_support": "You can't assign an category to this script",
+ "no_category_entity_reg": "To assign an category to an script it needs to have a unique ID.",
"delete": "[%key:ui::common::delete%]",
"duplicate": "[%key:ui::common::duplicate%]",
"empty_header": "Create your first script",
@@ -3655,8 +3660,13 @@
"headers": {
"state": "State",
"name": "Name",
- "last_activated": "Last activated"
+ "last_activated": "Last activated",
+ "category": "Category"
},
+ "edit_category": "[%key:ui::panel::config::automation::picker::edit_category%]",
+ "assign_category": "[%key:ui::panel::config::automation::picker::assign_category%]",
+ "no_category_support": "You can't assign an category to this scene",
+ "no_category_entity_reg": "To assign an category to an scene it needs to have a unique ID.",
"empty_header": "Create your first scene",
"empty_text": "Scenes capture entities' states, so you can re-experience the same scene later on. For example, a ''Watching TV'' scene that dims the living room lights, sets a warm white color and turns on the TV."
},