mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
20240329.0 (#20277)
This commit is contained in:
commit
d24d29e42f
@ -185,8 +185,8 @@
|
|||||||
"@types/tar": "6.1.11",
|
"@types/tar": "6.1.11",
|
||||||
"@types/ua-parser-js": "0.7.39",
|
"@types/ua-parser-js": "0.7.39",
|
||||||
"@types/webspeechapi": "0.0.29",
|
"@types/webspeechapi": "0.0.29",
|
||||||
"@typescript-eslint/eslint-plugin": "7.3.1",
|
"@typescript-eslint/eslint-plugin": "7.4.0",
|
||||||
"@typescript-eslint/parser": "7.3.1",
|
"@typescript-eslint/parser": "7.4.0",
|
||||||
"@web/dev-server": "0.1.38",
|
"@web/dev-server": "0.1.38",
|
||||||
"@web/dev-server-rollup": "0.4.1",
|
"@web/dev-server-rollup": "0.4.1",
|
||||||
"babel-loader": "9.1.3",
|
"babel-loader": "9.1.3",
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20240328.0"
|
version = "20240329.0"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "The Home Assistant frontend"
|
description = "The Home Assistant frontend"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -512,10 +512,6 @@ export class HaDataTable extends LitElement {
|
|||||||
items.push({ append: true, content: this.appendRow });
|
items.push({ append: true, content: this.appendRow });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasFab) {
|
|
||||||
items.push({ empty: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.groupColumn) {
|
if (this.groupColumn) {
|
||||||
const grouped = groupBy(items, (item) => item[this.groupColumn!]);
|
const grouped = groupBy(items, (item) => item[this.groupColumn!]);
|
||||||
if (grouped.undefined) {
|
if (grouped.undefined) {
|
||||||
@ -555,6 +551,10 @@ export class HaDataTable extends LitElement {
|
|||||||
} else {
|
} else {
|
||||||
this._items = items;
|
this._items = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.hasFab) {
|
||||||
|
this._items = [...this._items, { empty: true }];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this._items = data;
|
this._items = data;
|
||||||
}
|
}
|
||||||
|
@ -157,11 +157,11 @@ export class HaFilterBlueprints extends LitElement {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -78,13 +78,15 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
|
|||||||
class="ha-scrollbar"
|
class="ha-scrollbar"
|
||||||
activatable
|
activatable
|
||||||
>
|
>
|
||||||
<ha-list-item
|
${this._categories.length > 0
|
||||||
.selected=${!this.value?.length}
|
? html`<ha-list-item
|
||||||
.activated=${!this.value?.length}
|
.selected=${!this.value?.length}
|
||||||
>${this.hass.localize(
|
.activated=${!this.value?.length}
|
||||||
"ui.panel.config.category.filter.show_all"
|
>${this.hass.localize(
|
||||||
)}</ha-list-item
|
"ui.panel.config.category.filter.show_all"
|
||||||
>
|
)}</ha-list-item
|
||||||
|
>`
|
||||||
|
: nothing}
|
||||||
${this._categories.map(
|
${this._categories.map(
|
||||||
(category) =>
|
(category) =>
|
||||||
html`<ha-list-item
|
html`<ha-list-item
|
||||||
@ -142,7 +144,11 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
|
|||||||
: nothing}
|
: nothing}
|
||||||
</ha-expansion-panel>
|
</ha-expansion-panel>
|
||||||
${this.expanded
|
${this.expanded
|
||||||
? html`<ha-list-item graphic="icon" @click=${this._addCategory}>
|
? html`<ha-list-item
|
||||||
|
graphic="icon"
|
||||||
|
@click=${this._addCategory}
|
||||||
|
class="add"
|
||||||
|
>
|
||||||
<ha-svg-icon slot="graphic" .path=${mdiPlus}></ha-svg-icon>
|
<ha-svg-icon slot="graphic" .path=${mdiPlus}></ha-svg-icon>
|
||||||
${this.hass.localize("ui.panel.config.category.editor.add")}
|
${this.hass.localize("ui.panel.config.category.editor.add")}
|
||||||
</ha-list-item>`
|
</ha-list-item>`
|
||||||
@ -254,6 +260,7 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
|
|||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
border-bottom: 1px solid var(--divider-color);
|
border-bottom: 1px solid var(--divider-color);
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
:host([expanded]) {
|
:host([expanded]) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -277,11 +284,11 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
mwc-list {
|
mwc-list {
|
||||||
--mdc-list-item-meta-size: auto;
|
--mdc-list-item-meta-size: auto;
|
||||||
@ -291,6 +298,12 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
|
|||||||
.warning {
|
.warning {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
|
.add {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -185,11 +185,11 @@ export class HaFilterDevices extends LitElement {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
ha-check-list-item {
|
ha-check-list-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -199,11 +199,11 @@ export class HaFilterEntities extends LitElement {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
ha-check-list-item {
|
ha-check-list-item {
|
||||||
--mdc-list-item-graphic-margin: 16px;
|
--mdc-list-item-graphic-margin: 16px;
|
||||||
|
@ -267,11 +267,11 @@ export class HaFilterFloorAreas extends SubscribeMixin(LitElement) {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
ha-check-list-item {
|
ha-check-list-item {
|
||||||
--mdc-list-item-graphic-margin: 16px;
|
--mdc-list-item-graphic-margin: 16px;
|
||||||
|
@ -165,11 +165,11 @@ export class HaFilterIntegrations extends LitElement {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -3,10 +3,12 @@ import "@material/mwc-menu/mwc-menu-surface";
|
|||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { mdiPlus } from "@mdi/js";
|
||||||
import { computeCssColor } from "../common/color/compute-color";
|
import { computeCssColor } from "../common/color/compute-color";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import {
|
import {
|
||||||
LabelRegistryEntry,
|
LabelRegistryEntry,
|
||||||
|
createLabelRegistryEntry,
|
||||||
subscribeLabelRegistry,
|
subscribeLabelRegistry,
|
||||||
} from "../data/label_registry";
|
} from "../data/label_registry";
|
||||||
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
||||||
@ -16,6 +18,7 @@ import "./ha-check-list-item";
|
|||||||
import "./ha-expansion-panel";
|
import "./ha-expansion-panel";
|
||||||
import "./ha-icon";
|
import "./ha-icon";
|
||||||
import "./ha-label";
|
import "./ha-label";
|
||||||
|
import { showLabelDetailDialog } from "../panels/config/labels/show-dialog-label-detail";
|
||||||
|
|
||||||
@customElement("ha-filter-labels")
|
@customElement("ha-filter-labels")
|
||||||
export class HaFilterLabels extends SubscribeMixin(LitElement) {
|
export class HaFilterLabels extends SubscribeMixin(LitElement) {
|
||||||
@ -84,6 +87,16 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
|
|||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
</ha-expansion-panel>
|
</ha-expansion-panel>
|
||||||
|
${this.expanded
|
||||||
|
? html`<ha-list-item
|
||||||
|
graphic="icon"
|
||||||
|
@click=${this._addLabel}
|
||||||
|
class="add"
|
||||||
|
>
|
||||||
|
<ha-svg-icon slot="graphic" .path=${mdiPlus}></ha-svg-icon>
|
||||||
|
${this.hass.localize("ui.panel.config.labels.add_label")}
|
||||||
|
</ha-list-item>`
|
||||||
|
: nothing}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,11 +105,17 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!this.expanded) return;
|
if (!this.expanded) return;
|
||||||
this.renderRoot.querySelector("mwc-list")!.style.height =
|
this.renderRoot.querySelector("mwc-list")!.style.height =
|
||||||
`${this.clientHeight - 49}px`;
|
`${this.clientHeight - (49 + 48)}px`;
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _addLabel() {
|
||||||
|
showLabelDetailDialog(this, {
|
||||||
|
createEntry: (values) => createLabelRegistryEntry(this.hass, values),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private _expandedWillChange(ev) {
|
private _expandedWillChange(ev) {
|
||||||
this._shouldRender = ev.detail.expanded;
|
this._shouldRender = ev.detail.expanded;
|
||||||
}
|
}
|
||||||
@ -134,6 +153,7 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
|
|||||||
haStyleScrollbar,
|
haStyleScrollbar,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
|
position: relative;
|
||||||
border-bottom: 1px solid var(--divider-color);
|
border-bottom: 1px solid var(--divider-color);
|
||||||
}
|
}
|
||||||
:host([expanded]) {
|
:host([expanded]) {
|
||||||
@ -158,11 +178,11 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
.warning {
|
.warning {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
@ -171,6 +191,12 @@ export class HaFilterLabels extends SubscribeMixin(LitElement) {
|
|||||||
--ha-label-background-color: var(--color, var(--grey-color));
|
--ha-label-background-color: var(--color, var(--grey-color));
|
||||||
--ha-label-background-opacity: 0.5;
|
--ha-label-background-opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
.add {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -147,11 +147,11 @@ export class HaFilterStates extends LitElement {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -38,10 +38,14 @@ import "./ha-list-item";
|
|||||||
|
|
||||||
type ScorableFloorRegistryEntry = ScorableTextItem & FloorRegistryEntry;
|
type ScorableFloorRegistryEntry = ScorableTextItem & FloorRegistryEntry;
|
||||||
|
|
||||||
|
const ADD_NEW_ID = "___ADD_NEW___";
|
||||||
|
const NO_FLOORS_ID = "___NO_FLOORS___";
|
||||||
|
const ADD_NEW_SUGGESTION_ID = "___ADD_NEW_SUGGESTION___";
|
||||||
|
|
||||||
const rowRenderer: ComboBoxLitRenderer<FloorRegistryEntry> = (item) =>
|
const rowRenderer: ComboBoxLitRenderer<FloorRegistryEntry> = (item) =>
|
||||||
html`<ha-list-item
|
html`<ha-list-item
|
||||||
graphic="icon"
|
graphic="icon"
|
||||||
class=${classMap({ "add-new": item.floor_id === "add_new" })}
|
class=${classMap({ "add-new": item.floor_id === ADD_NEW_ID })}
|
||||||
>
|
>
|
||||||
<ha-floor-icon slot="graphic" .floor=${item}></ha-floor-icon>
|
<ha-floor-icon slot="graphic" .floor=${item}></ha-floor-icon>
|
||||||
${item.name}
|
${item.name}
|
||||||
@ -146,18 +150,6 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
|||||||
noAdd: this["noAdd"],
|
noAdd: this["noAdd"],
|
||||||
excludeFloors: this["excludeFloors"]
|
excludeFloors: this["excludeFloors"]
|
||||||
): FloorRegistryEntry[] => {
|
): FloorRegistryEntry[] => {
|
||||||
if (!floors.length) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
floor_id: "no_floors",
|
|
||||||
name: this.hass.localize("ui.components.floor-picker.no_floors"),
|
|
||||||
icon: null,
|
|
||||||
level: 0,
|
|
||||||
aliases: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
let deviceEntityLookup: DeviceEntityDisplayLookup = {};
|
let deviceEntityLookup: DeviceEntityDisplayLookup = {};
|
||||||
let inputDevices: DeviceRegistryEntry[] | undefined;
|
let inputDevices: DeviceRegistryEntry[] | undefined;
|
||||||
let inputEntities: EntityRegistryDisplayEntry[] | undefined;
|
let inputEntities: EntityRegistryDisplayEntry[] | undefined;
|
||||||
@ -297,10 +289,10 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
|||||||
if (!outputFloors.length) {
|
if (!outputFloors.length) {
|
||||||
outputFloors = [
|
outputFloors = [
|
||||||
{
|
{
|
||||||
floor_id: "no_floors",
|
floor_id: NO_FLOORS_ID,
|
||||||
name: this.hass.localize("ui.components.floor-picker.no_match"),
|
name: this.hass.localize("ui.components.floor-picker.no_floors"),
|
||||||
icon: null,
|
icon: null,
|
||||||
level: 0,
|
level: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -311,10 +303,10 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
|||||||
: [
|
: [
|
||||||
...outputFloors,
|
...outputFloors,
|
||||||
{
|
{
|
||||||
floor_id: "add_new",
|
floor_id: ADD_NEW_ID,
|
||||||
name: this.hass.localize("ui.components.floor-picker.add_new"),
|
name: this.hass.localize("ui.components.floor-picker.add_new"),
|
||||||
icon: "mdi:plus",
|
icon: "mdi:plus",
|
||||||
level: 0,
|
level: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -341,7 +333,7 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
|||||||
this.excludeFloors
|
this.excludeFloors
|
||||||
).map((floor) => ({
|
).map((floor) => ({
|
||||||
...floor,
|
...floor,
|
||||||
strings: [floor.floor_id, floor.name], // ...floor.aliases
|
strings: [floor.floor_id, floor.name, ...floor.aliases],
|
||||||
}));
|
}));
|
||||||
this.comboBox.items = floors;
|
this.comboBox.items = floors;
|
||||||
this.comboBox.filteredItems = floors;
|
this.comboBox.filteredItems = floors;
|
||||||
@ -385,20 +377,36 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
const filteredItems = fuzzyFilterSort<ScorableFloorRegistryEntry>(
|
const filteredItems = fuzzyFilterSort<ScorableFloorRegistryEntry>(
|
||||||
filterString,
|
filterString,
|
||||||
target.items || []
|
target.items?.filter(
|
||||||
|
(item) => ![NO_FLOORS_ID, ADD_NEW_ID].includes(item.label_id)
|
||||||
|
) || []
|
||||||
);
|
);
|
||||||
if (!this.noAdd && filteredItems?.length === 0) {
|
if (filteredItems.length === 0) {
|
||||||
this._suggestion = filterString;
|
if (this.noAdd) {
|
||||||
this.comboBox.filteredItems = [
|
this.comboBox.filteredItems = [
|
||||||
{
|
{
|
||||||
floor_id: "add_new_suggestion",
|
floor_id: NO_FLOORS_ID,
|
||||||
name: this.hass.localize(
|
name: this.hass.localize("ui.components.floor-picker.no_floors"),
|
||||||
"ui.components.floor-picker.add_new_sugestion",
|
icon: null,
|
||||||
{ name: this._suggestion }
|
level: null,
|
||||||
),
|
aliases: [],
|
||||||
picture: null,
|
},
|
||||||
},
|
] as FloorRegistryEntry[];
|
||||||
];
|
} else {
|
||||||
|
this._suggestion = filterString;
|
||||||
|
this.comboBox.filteredItems = [
|
||||||
|
{
|
||||||
|
floor_id: ADD_NEW_SUGGESTION_ID,
|
||||||
|
name: this.hass.localize(
|
||||||
|
"ui.components.floor-picker.add_new_sugestion",
|
||||||
|
{ name: this._suggestion }
|
||||||
|
),
|
||||||
|
icon: "mdi:plus",
|
||||||
|
level: null,
|
||||||
|
aliases: [],
|
||||||
|
},
|
||||||
|
] as FloorRegistryEntry[];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.comboBox.filteredItems = filteredItems;
|
this.comboBox.filteredItems = filteredItems;
|
||||||
}
|
}
|
||||||
@ -416,11 +424,13 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
|||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
let newValue = ev.detail.value;
|
let newValue = ev.detail.value;
|
||||||
|
|
||||||
if (newValue === "no_floors") {
|
if (newValue === NO_FLOORS_ID) {
|
||||||
newValue = "";
|
newValue = "";
|
||||||
|
this.comboBox.setInputValue("");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!["add_new_suggestion", "add_new"].includes(newValue)) {
|
if (![ADD_NEW_SUGGESTION_ID, ADD_NEW_ID].includes(newValue)) {
|
||||||
if (newValue !== this._value) {
|
if (newValue !== this._value) {
|
||||||
this._setValue(newValue);
|
this._setValue(newValue);
|
||||||
}
|
}
|
||||||
@ -438,7 +448,7 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
|||||||
"ui.components.floor-picker.add_dialog.name"
|
"ui.components.floor-picker.add_dialog.name"
|
||||||
),
|
),
|
||||||
defaultValue:
|
defaultValue:
|
||||||
newValue === "add_new_suggestion" ? this._suggestion : undefined,
|
newValue === ADD_NEW_SUGGESTION_ID ? this._suggestion : undefined,
|
||||||
confirm: async (name) => {
|
confirm: async (name) => {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return;
|
return;
|
||||||
|
@ -385,8 +385,8 @@ export class HaLabelPicker extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
const filteredItems = fuzzyFilterSort<ScorableLabelItem>(
|
const filteredItems = fuzzyFilterSort<ScorableLabelItem>(
|
||||||
filterString,
|
filterString,
|
||||||
target.items?.filter((item) =>
|
target.items?.filter(
|
||||||
[NO_LABELS_ID, ADD_NEW_ID].includes(item.ignoreFilter)
|
(item) => ![NO_LABELS_ID, ADD_NEW_ID].includes(item.label_id)
|
||||||
) || []
|
) || []
|
||||||
);
|
);
|
||||||
if (filteredItems.length === 0) {
|
if (filteredItems.length === 0) {
|
||||||
|
38
src/components/ha-outlined-text-field.ts
Normal file
38
src/components/ha-outlined-text-field.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field";
|
||||||
|
import "element-internals-polyfill";
|
||||||
|
import { css } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
|
||||||
|
@customElement("ha-outlined-text-field")
|
||||||
|
export class HaOutlinedTextField extends MdOutlinedTextField {
|
||||||
|
static override styles = [
|
||||||
|
...super.styles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
--md-sys-color-on-surface: var(--primary-text-color);
|
||||||
|
--md-sys-color-primary: var(--primary-text-color);
|
||||||
|
--md-outlined-text-field-input-text-color: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-surface-variant: var(--secondary-text-color);
|
||||||
|
--md-outlined-field-outline-color: var(--outline-color);
|
||||||
|
--md-outlined-field-focus-outline-color: var(--primary-color);
|
||||||
|
--md-outlined-field-hover-outline-color: var(--outline-hover-color);
|
||||||
|
}
|
||||||
|
:host([dense]) {
|
||||||
|
--md-outlined-field-top-space: 5.5px;
|
||||||
|
--md-outlined-field-bottom-space: 5.5px;
|
||||||
|
--md-outlined-field-container-shape-start-start: 10px;
|
||||||
|
--md-outlined-field-container-shape-start-end: 10px;
|
||||||
|
--md-outlined-field-container-shape-end-end: 10px;
|
||||||
|
--md-outlined-field-container-shape-end-start: 10px;
|
||||||
|
--md-outlined-field-focus-outline-width: 1px;
|
||||||
|
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-outlined-text-field": HaOutlinedTextField;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import "@material/web/textfield/outlined-text-field";
|
|
||||||
import type { MdOutlinedTextField } from "@material/web/textfield/outlined-text-field";
|
|
||||||
import { mdiMagnify } from "@mdi/js";
|
import { mdiMagnify } from "@mdi/js";
|
||||||
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
|
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
import "./ha-icon-button";
|
import "./ha-icon-button";
|
||||||
|
import "./ha-outlined-text-field";
|
||||||
|
import type { HaOutlinedTextField } from "./ha-outlined-text-field";
|
||||||
import "./ha-svg-icon";
|
import "./ha-svg-icon";
|
||||||
|
|
||||||
@customElement("search-input-outlined")
|
@customElement("search-input-outlined")
|
||||||
@ -30,19 +30,22 @@ class SearchInputOutlined extends LitElement {
|
|||||||
this._input?.focus();
|
this._input?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@query("md-outlined-text-field", true) private _input!: MdOutlinedTextField;
|
@query("ha-outlined-text-field", true) private _input!: HaOutlinedTextField;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
const placeholder =
|
||||||
|
this.placeholder || this.hass.localize("ui.common.search");
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<md-outlined-text-field
|
<ha-outlined-text-field
|
||||||
.autofocus=${this.autofocus}
|
.autofocus=${this.autofocus}
|
||||||
.aria-label=${this.label || this.hass.localize("ui.common.search")}
|
.aria-label=${this.label || this.hass.localize("ui.common.search")}
|
||||||
.placeholder=${this.placeholder ||
|
.placeholder=${placeholder}
|
||||||
this.hass.localize("ui.common.search")}
|
|
||||||
.value=${this.filter || ""}
|
.value=${this.filter || ""}
|
||||||
icon
|
icon
|
||||||
.iconTrailing=${this.filter || this.suffix}
|
.iconTrailing=${this.filter || this.suffix}
|
||||||
@input=${this._filterInputChanged}
|
@input=${this._filterInputChanged}
|
||||||
|
dense
|
||||||
>
|
>
|
||||||
<slot name="prefix" slot="leading-icon">
|
<slot name="prefix" slot="leading-icon">
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
@ -51,7 +54,7 @@ class SearchInputOutlined extends LitElement {
|
|||||||
.path=${mdiMagnify}
|
.path=${mdiMagnify}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
</slot>
|
</slot>
|
||||||
</md-outlined-text-field>
|
</ha-outlined-text-field>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,40 +70,21 @@ class SearchInputOutlined extends LitElement {
|
|||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
/* For iOS */
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
md-outlined-text-field {
|
ha-outlined-text-field {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
--md-sys-color-on-surface: var(--primary-text-color);
|
|
||||||
--md-sys-color-primary: var(--primary-text-color);
|
|
||||||
--md-outlined-text-field-input-text-color: var(--primary-text-color);
|
|
||||||
--md-sys-color-on-surface-variant: var(--secondary-text-color);
|
|
||||||
--md-outlined-field-top-space: 5.5px;
|
|
||||||
--md-outlined-field-bottom-space: 5.5px;
|
|
||||||
--md-outlined-field-outline-color: var(--outline-color);
|
|
||||||
--md-outlined-field-container-shape-start-start: 10px;
|
|
||||||
--md-outlined-field-container-shape-start-end: 10px;
|
|
||||||
--md-outlined-field-container-shape-end-end: 10px;
|
|
||||||
--md-outlined-field-container-shape-end-start: 10px;
|
|
||||||
--md-outlined-field-focus-outline-width: 1px;
|
|
||||||
--md-outlined-field-focus-outline-color: var(--primary-color);
|
|
||||||
}
|
}
|
||||||
ha-svg-icon,
|
ha-svg-icon,
|
||||||
ha-icon-button {
|
ha-icon-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
ha-svg-icon {
|
ha-svg-icon {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
.clear-button {
|
|
||||||
--mdc-icon-size: 20px;
|
|
||||||
}
|
|
||||||
.trailing {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import { computeDomain } from "../common/entity/compute_domain";
|
|||||||
|
|
||||||
export { subscribeEntityRegistryDisplay } from "./ws-entity_registry_display";
|
export { subscribeEntityRegistryDisplay } from "./ws-entity_registry_display";
|
||||||
|
|
||||||
type entityCategory = "config" | "diagnostic";
|
type EntityCategory = "config" | "diagnostic";
|
||||||
|
|
||||||
export interface EntityRegistryDisplayEntry {
|
export interface EntityRegistryDisplayEntry {
|
||||||
entity_id: string;
|
entity_id: string;
|
||||||
@ -20,7 +20,7 @@ export interface EntityRegistryDisplayEntry {
|
|||||||
area_id?: string;
|
area_id?: string;
|
||||||
labels: string[];
|
labels: string[];
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
entity_category?: entityCategory;
|
entity_category?: EntityCategory;
|
||||||
translation_key?: string;
|
translation_key?: string;
|
||||||
platform?: string;
|
platform?: string;
|
||||||
display_precision?: number;
|
display_precision?: number;
|
||||||
@ -40,7 +40,7 @@ export interface EntityRegistryDisplayEntryResponse {
|
|||||||
hb?: boolean;
|
hb?: boolean;
|
||||||
dp?: number;
|
dp?: number;
|
||||||
}[];
|
}[];
|
||||||
entity_categories: Record<number, entityCategory>;
|
entity_categories: Record<number, EntityCategory>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EntityRegistryEntry {
|
export interface EntityRegistryEntry {
|
||||||
@ -55,7 +55,7 @@ export interface EntityRegistryEntry {
|
|||||||
labels: string[];
|
labels: string[];
|
||||||
disabled_by: "user" | "device" | "integration" | "config_entry" | null;
|
disabled_by: "user" | "device" | "integration" | "config_entry" | null;
|
||||||
hidden_by: Exclude<EntityRegistryEntry["disabled_by"], "config_entry">;
|
hidden_by: Exclude<EntityRegistryEntry["disabled_by"], "config_entry">;
|
||||||
entity_category: entityCategory | null;
|
entity_category: EntityCategory | null;
|
||||||
has_entity_name: boolean;
|
has_entity_name: boolean;
|
||||||
original_name?: string;
|
original_name?: string;
|
||||||
unique_id: string;
|
unique_id: string;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||||
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
|
import "@material/web/menu/menu";
|
||||||
|
import type { MdMenu } from "@material/web/menu/menu";
|
||||||
|
import "@material/web/menu/menu-item";
|
||||||
import {
|
import {
|
||||||
mdiArrowDown,
|
mdiArrowDown,
|
||||||
mdiArrowUp,
|
mdiArrowUp,
|
||||||
@ -19,6 +22,7 @@ import {
|
|||||||
nothing,
|
nothing,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { LocalizeFunc } from "../common/translations/localize";
|
import { LocalizeFunc } from "../common/translations/localize";
|
||||||
import "../components/chips/ha-assist-chip";
|
import "../components/chips/ha-assist-chip";
|
||||||
@ -173,6 +177,10 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
|
|
||||||
@query("ha-data-table", true) private _dataTable!: HaDataTable;
|
@query("ha-data-table", true) private _dataTable!: HaDataTable;
|
||||||
|
|
||||||
|
@query("#group-by-menu") private _groupByMenu!: MdMenu;
|
||||||
|
|
||||||
|
@query("#sort-by-menu") private _sortByMenu!: MdMenu;
|
||||||
|
|
||||||
private _showPaneController = new ResizeController(this, {
|
private _showPaneController = new ResizeController(this, {
|
||||||
callback: (entries) => entries[0]?.contentRect.width > 750,
|
callback: (entries) => entries[0]?.contentRect.width > 750,
|
||||||
});
|
});
|
||||||
@ -187,6 +195,14 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _toggleGroupBy() {
|
||||||
|
this._groupByMenu.open = !this._groupByMenu.open;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toggleSortBy() {
|
||||||
|
this._sortByMenu.open = !this._sortByMenu.open;
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const localize = this.localizeFunc || this.hass.localize;
|
const localize = this.localizeFunc || this.hass.localize;
|
||||||
const showPane = this._showPaneController.value ?? !this.narrow;
|
const showPane = this._showPaneController.value ?? !this.narrow;
|
||||||
@ -226,73 +242,35 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
</search-input-outlined>`;
|
</search-input-outlined>`;
|
||||||
|
|
||||||
const sortByMenu = Object.values(this.columns).find((col) => col.sortable)
|
const sortByMenu = Object.values(this.columns).find((col) => col.sortable)
|
||||||
? html`<ha-button-menu fixed>
|
? html`
|
||||||
<ha-assist-chip
|
<ha-assist-chip
|
||||||
.label=${localize("ui.components.subpage-data-table.sort_by", {
|
.label=${localize("ui.components.subpage-data-table.sort_by", {
|
||||||
sortColumn: this._sortColumn
|
sortColumn: this._sortColumn
|
||||||
? ` ${this.columns[this._sortColumn].title || this.columns[this._sortColumn].label}`
|
? ` ${this.columns[this._sortColumn].title || this.columns[this._sortColumn].label}`
|
||||||
: "",
|
: "",
|
||||||
})}
|
})}
|
||||||
slot="trigger"
|
id="sort-by-anchor"
|
||||||
|
@click=${this._toggleSortBy}
|
||||||
>
|
>
|
||||||
<ha-svg-icon slot="trailing-icon" .path=${mdiMenuDown}></ha-svg-icon
|
<ha-svg-icon slot="trailing-icon" .path=${mdiMenuDown}></ha-svg-icon
|
||||||
></ha-assist-chip>
|
></ha-assist-chip>
|
||||||
${Object.entries(this.columns).map(([id, column]) =>
|
`
|
||||||
column.sortable
|
|
||||||
? html`<ha-list-item
|
|
||||||
.value=${id}
|
|
||||||
@request-selected=${this._handleSortBy}
|
|
||||||
hasMeta
|
|
||||||
.activated=${id === this._sortColumn}
|
|
||||||
>
|
|
||||||
${this._sortColumn === id
|
|
||||||
? html`<ha-svg-icon
|
|
||||||
slot="meta"
|
|
||||||
.path=${this._sortDirection === "desc"
|
|
||||||
? mdiArrowDown
|
|
||||||
: mdiArrowUp}
|
|
||||||
></ha-svg-icon>`
|
|
||||||
: nothing}
|
|
||||||
${column.title || column.label}
|
|
||||||
</ha-list-item>`
|
|
||||||
: nothing
|
|
||||||
)}
|
|
||||||
</ha-button-menu>`
|
|
||||||
: nothing;
|
: nothing;
|
||||||
|
|
||||||
const groupByMenu = Object.values(this.columns).find((col) => col.groupable)
|
const groupByMenu = Object.values(this.columns).find((col) => col.groupable)
|
||||||
? html`<ha-button-menu fixed>
|
? html`
|
||||||
<ha-assist-chip
|
<ha-assist-chip
|
||||||
.label=${localize("ui.components.subpage-data-table.group_by", {
|
.label=${localize("ui.components.subpage-data-table.group_by", {
|
||||||
groupColumn: this._groupColumn
|
groupColumn: this._groupColumn
|
||||||
? ` ${this.columns[this._groupColumn].title || this.columns[this._groupColumn].label}`
|
? ` ${this.columns[this._groupColumn].title || this.columns[this._groupColumn].label}`
|
||||||
: "",
|
: "",
|
||||||
})}
|
})}
|
||||||
slot="trigger"
|
id="group-by-anchor"
|
||||||
|
@click=${this._toggleGroupBy}
|
||||||
>
|
>
|
||||||
<ha-svg-icon slot="trailing-icon" .path=${mdiMenuDown}></ha-svg-icon
|
<ha-svg-icon slot="trailing-icon" .path=${mdiMenuDown}></ha-svg-icon
|
||||||
></ha-assist-chip>
|
></ha-assist-chip>
|
||||||
${Object.entries(this.columns).map(([id, column]) =>
|
`
|
||||||
column.groupable
|
|
||||||
? html`<ha-list-item
|
|
||||||
.value=${id}
|
|
||||||
@request-selected=${this._handleGroupBy}
|
|
||||||
.activated=${id === this._groupColumn}
|
|
||||||
>
|
|
||||||
${column.title || column.label}
|
|
||||||
</ha-list-item> `
|
|
||||||
: nothing
|
|
||||||
)}
|
|
||||||
<li divider role="separator"></li>
|
|
||||||
<ha-list-item
|
|
||||||
.value=${undefined}
|
|
||||||
@request-selected=${this._handleGroupBy}
|
|
||||||
.activated=${this._groupColumn === undefined}
|
|
||||||
>${localize(
|
|
||||||
"ui.components.subpage-data-table.dont_group_by"
|
|
||||||
)}</ha-list-item
|
|
||||||
>
|
|
||||||
</ha-button-menu>`
|
|
||||||
: nothing;
|
: nothing;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@ -431,6 +409,58 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
</ha-data-table>`}
|
</ha-data-table>`}
|
||||||
<div slot="fab"><slot name="fab"></slot></div>
|
<div slot="fab"><slot name="fab"></slot></div>
|
||||||
</hass-tabs-subpage>
|
</hass-tabs-subpage>
|
||||||
|
<md-menu anchor="group-by-anchor" id="group-by-menu" positioning="fixed">
|
||||||
|
${Object.entries(this.columns).map(([id, column]) =>
|
||||||
|
column.groupable
|
||||||
|
? html`
|
||||||
|
<md-menu-item
|
||||||
|
.value=${id}
|
||||||
|
@click=${this._handleGroupBy}
|
||||||
|
.selected=${id === this._groupColumn}
|
||||||
|
class=${classMap({ selected: id === this._groupColumn })}
|
||||||
|
>
|
||||||
|
${column.title || column.label}
|
||||||
|
</md-menu-item>
|
||||||
|
`
|
||||||
|
: nothing
|
||||||
|
)}
|
||||||
|
<li divider role="separator"></li>
|
||||||
|
<md-menu-item
|
||||||
|
.value=${undefined}
|
||||||
|
@click=${this._handleGroupBy}
|
||||||
|
.selected=${this._groupColumn === undefined}
|
||||||
|
class=${classMap({ selected: this._groupColumn === undefined })}
|
||||||
|
>${localize(
|
||||||
|
"ui.components.subpage-data-table.dont_group_by"
|
||||||
|
)}</md-menu-item
|
||||||
|
>
|
||||||
|
</md-menu>
|
||||||
|
<md-menu anchor="sort-by-anchor" id="sort-by-menu" positioning="fixed">
|
||||||
|
${Object.entries(this.columns).map(([id, column]) =>
|
||||||
|
column.sortable
|
||||||
|
? html`
|
||||||
|
<md-menu-item
|
||||||
|
.value=${id}
|
||||||
|
@click=${this._handleSortBy}
|
||||||
|
.selected=${id === this._sortColumn}
|
||||||
|
class=${classMap({ selected: id === this._sortColumn })}
|
||||||
|
>
|
||||||
|
${this._sortColumn === id
|
||||||
|
? html`
|
||||||
|
<ha-svg-icon
|
||||||
|
slot="end"
|
||||||
|
.path=${this._sortDirection === "desc"
|
||||||
|
? mdiArrowDown
|
||||||
|
: mdiArrowUp}
|
||||||
|
></ha-svg-icon>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
${column.title || column.label}
|
||||||
|
</md-menu-item>
|
||||||
|
`
|
||||||
|
: nothing
|
||||||
|
)}
|
||||||
|
</md-menu>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,6 +479,7 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
|
|
||||||
private _handleSortBy(ev) {
|
private _handleSortBy(ev) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
const columnId = ev.currentTarget.value;
|
const columnId = ev.currentTarget.value;
|
||||||
if (!this._sortDirection || this._sortColumn !== columnId) {
|
if (!this._sortDirection || this._sortColumn !== columnId) {
|
||||||
this._sortDirection = "asc";
|
this._sortDirection = "asc";
|
||||||
@ -611,11 +642,11 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--primary-color);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: var(--text-accent-color, var(--text-primary-color));
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.narrow-header-row {
|
.narrow-header-row {
|
||||||
@ -656,13 +687,6 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
ha-assist-chip {
|
ha-assist-chip {
|
||||||
--ha-assist-chip-container-shape: 10px;
|
--ha-assist-chip-container-shape: 10px;
|
||||||
}
|
}
|
||||||
ha-button-menu {
|
|
||||||
--mdc-list-item-meta-size: 16px;
|
|
||||||
--mdc-list-item-meta-display: flex;
|
|
||||||
}
|
|
||||||
ha-button-menu ha-assist-chip {
|
|
||||||
--md-assist-chip-trailing-space: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-mode-chip {
|
.select-mode-chip {
|
||||||
--md-assist-chip-icon-label-space: 0;
|
--md-assist-chip-icon-label-space: 0;
|
||||||
@ -688,6 +712,25 @@ export class HaTabsSubpageDataTable extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
/* TODO: Migrate to ha-menu and ha-menu-item */
|
||||||
|
md-menu {
|
||||||
|
--md-menu-container-color: var(--card-background-color);
|
||||||
|
}
|
||||||
|
md-menu-item {
|
||||||
|
--md-menu-item-label-text-color: var(--primary-text-color);
|
||||||
|
--mdc-icon-size: 16px;
|
||||||
|
--md-menu-item-selected-container-color: rgba(
|
||||||
|
var(--rgb-primary-color),
|
||||||
|
0.15
|
||||||
|
);
|
||||||
|
}
|
||||||
|
md-menu-item.selected {
|
||||||
|
--md-menu-item-label-text-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
#sort-by-anchor,
|
||||||
|
#group-by-anchor {
|
||||||
|
--md-assist-chip-trailing-space: 8px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
|||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
css,
|
css,
|
||||||
html,
|
html,
|
||||||
@ -38,13 +39,15 @@ import type {
|
|||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
|
import "../../../components/data-table/ha-data-table-labels";
|
||||||
import "../../../components/entity/ha-entity-toggle";
|
import "../../../components/entity/ha-entity-toggle";
|
||||||
import "../../../components/ha-fab";
|
import "../../../components/ha-fab";
|
||||||
import "../../../components/ha-filter-floor-areas";
|
|
||||||
import "../../../components/ha-filter-blueprints";
|
import "../../../components/ha-filter-blueprints";
|
||||||
import "../../../components/ha-filter-categories";
|
import "../../../components/ha-filter-categories";
|
||||||
import "../../../components/ha-filter-devices";
|
import "../../../components/ha-filter-devices";
|
||||||
import "../../../components/ha-filter-entities";
|
import "../../../components/ha-filter-entities";
|
||||||
|
import "../../../components/ha-filter-floor-areas";
|
||||||
|
import "../../../components/ha-filter-labels";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-icon-overflow-menu";
|
import "../../../components/ha-icon-overflow-menu";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
@ -64,6 +67,10 @@ import {
|
|||||||
import { fullEntitiesContext } from "../../../data/context";
|
import { fullEntitiesContext } from "../../../data/context";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
|
import {
|
||||||
|
LabelRegistryEntry,
|
||||||
|
subscribeLabelRegistry,
|
||||||
|
} from "../../../data/label_registry";
|
||||||
import { findRelated } from "../../../data/search";
|
import { findRelated } from "../../../data/search";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@ -77,12 +84,6 @@ import { documentationUrl } from "../../../util/documentation-url";
|
|||||||
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import { showNewAutomationDialog } from "./show-dialog-new-automation";
|
import { showNewAutomationDialog } from "./show-dialog-new-automation";
|
||||||
import "../../../components/data-table/ha-data-table-labels";
|
|
||||||
import {
|
|
||||||
LabelRegistryEntry,
|
|
||||||
subscribeLabelRegistry,
|
|
||||||
} from "../../../data/label_registry";
|
|
||||||
import "../../../components/ha-filter-labels";
|
|
||||||
|
|
||||||
type AutomationItem = AutomationEntity & {
|
type AutomationItem = AutomationEntity & {
|
||||||
name: string;
|
name: string;
|
||||||
@ -509,6 +510,13 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (changedProps.has("_entityReg")) {
|
||||||
|
this._applyFilters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
if (this._searchParms.has("blueprint")) {
|
if (this._searchParms.has("blueprint")) {
|
||||||
this._filterBlueprint();
|
this._filterBlueprint();
|
||||||
|
@ -179,7 +179,9 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
const filteredItems = fuzzyFilterSort<ScorableCategoryRegistryEntry>(
|
const filteredItems = fuzzyFilterSort<ScorableCategoryRegistryEntry>(
|
||||||
filterString,
|
filterString,
|
||||||
target.items || []
|
target.items?.filter(
|
||||||
|
(item) => ![NO_CATEGORIES_ID, ADD_NEW_ID].includes(item.category_id)
|
||||||
|
) || []
|
||||||
);
|
);
|
||||||
if (filteredItems?.length === 0) {
|
if (filteredItems?.length === 0) {
|
||||||
if (this.noAdd) {
|
if (this.noAdd) {
|
||||||
@ -224,6 +226,8 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
if (newValue === NO_CATEGORIES_ID) {
|
if (newValue === NO_CATEGORIES_ID) {
|
||||||
newValue = "";
|
newValue = "";
|
||||||
|
this.comboBox.setInputValue("");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![ADD_NEW_SUGGESTION_ID, ADD_NEW_ID].includes(newValue)) {
|
if (![ADD_NEW_SUGGESTION_ID, ADD_NEW_ID].includes(newValue)) {
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
nothing,
|
nothing,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
|
|
||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
@ -24,16 +25,18 @@ import {
|
|||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
|
import "../../../components/data-table/ha-data-table-labels";
|
||||||
import "../../../components/entity/ha-battery-icon";
|
import "../../../components/entity/ha-battery-icon";
|
||||||
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-check-list-item";
|
import "../../../components/ha-check-list-item";
|
||||||
import "../../../components/ha-fab";
|
import "../../../components/ha-fab";
|
||||||
import "../../../components/ha-filter-devices";
|
import "../../../components/ha-filter-devices";
|
||||||
import "../../../components/ha-filter-floor-areas";
|
import "../../../components/ha-filter-floor-areas";
|
||||||
import "../../../components/ha-filter-integrations";
|
import "../../../components/ha-filter-integrations";
|
||||||
|
import "../../../components/ha-filter-labels";
|
||||||
import "../../../components/ha-filter-states";
|
import "../../../components/ha-filter-states";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-alert";
|
|
||||||
import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries";
|
import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries";
|
||||||
import { fullEntitiesContext } from "../../../data/context";
|
import { fullEntitiesContext } from "../../../data/context";
|
||||||
import {
|
import {
|
||||||
@ -47,7 +50,12 @@ import {
|
|||||||
findBatteryEntity,
|
findBatteryEntity,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import { IntegrationManifest } from "../../../data/integration";
|
import { IntegrationManifest } from "../../../data/integration";
|
||||||
|
import {
|
||||||
|
LabelRegistryEntry,
|
||||||
|
subscribeLabelRegistry,
|
||||||
|
} from "../../../data/label_registry";
|
||||||
import "../../../layouts/hass-tabs-subpage-data-table";
|
import "../../../layouts/hass-tabs-subpage-data-table";
|
||||||
|
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { brandsUrl } from "../../../util/brands-url";
|
import { brandsUrl } from "../../../util/brands-url";
|
||||||
@ -60,10 +68,11 @@ interface DeviceRowData extends DeviceRegistryEntry {
|
|||||||
area?: string;
|
area?: string;
|
||||||
integration?: string;
|
integration?: string;
|
||||||
battery_entity?: [string | undefined, string | undefined];
|
battery_entity?: [string | undefined, string | undefined];
|
||||||
|
label_entries: EntityRegistryEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("ha-config-devices-dashboard")
|
@customElement("ha-config-devices-dashboard")
|
||||||
export class HaConfigDeviceDashboard extends LitElement {
|
export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow = false;
|
@property({ type: Boolean }) public narrow = false;
|
||||||
@ -91,6 +100,9 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
|
|
||||||
@state() private _expandedFilter?: string;
|
@state() private _expandedFilter?: string;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_labels!: LabelRegistryEntry[];
|
||||||
|
|
||||||
private _ignoreLocationChange = false;
|
private _ignoreLocationChange = false;
|
||||||
|
|
||||||
public connectedCallback() {
|
public connectedCallback() {
|
||||||
@ -190,11 +202,17 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
string,
|
string,
|
||||||
{ value: string[] | undefined; items: Set<string> | undefined }
|
{ value: string[] | undefined; items: Set<string> | undefined }
|
||||||
>,
|
>,
|
||||||
localize: LocalizeFunc
|
localize: LocalizeFunc,
|
||||||
|
labelReg?: LabelRegistryEntry[]
|
||||||
) => {
|
) => {
|
||||||
// Some older installations might have devices pointing at invalid entryIDs
|
// Some older installations might have devices pointing at invalid entryIDs
|
||||||
// So we guard for that.
|
// So we guard for that.
|
||||||
let outputDevices: DeviceRowData[] = Object.values(devices);
|
let outputDevices: DeviceRowData[] = Object.values(devices).map(
|
||||||
|
(device) => ({
|
||||||
|
...device,
|
||||||
|
label_entries: [],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const deviceEntityLookup: DeviceEntityLookup = {};
|
const deviceEntityLookup: DeviceEntityLookup = {};
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
@ -221,16 +239,16 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
|
|
||||||
const filteredDomains = new Set<string>();
|
const filteredDomains = new Set<string>();
|
||||||
|
|
||||||
Object.entries(filters).forEach(([key, flter]) => {
|
Object.entries(filters).forEach(([key, filter]) => {
|
||||||
if (key === "config_entry" && flter.value?.length) {
|
if (key === "config_entry" && filter.value?.length) {
|
||||||
outputDevices = outputDevices.filter((device) =>
|
outputDevices = outputDevices.filter((device) =>
|
||||||
device.config_entries.some((entryId) =>
|
device.config_entries.some((entryId) =>
|
||||||
flter.value?.includes(entryId)
|
filter.value?.includes(entryId)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const configEntries = entries.filter(
|
const configEntries = entries.filter(
|
||||||
(entry) => entry.entry_id && flter.value?.includes(entry.entry_id)
|
(entry) => entry.entry_id && filter.value?.includes(entry.entry_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
configEntries.forEach((configEntry) => {
|
configEntries.forEach((configEntry) => {
|
||||||
@ -239,17 +257,21 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
if (configEntries.length === 1) {
|
if (configEntries.length === 1) {
|
||||||
filteredConfigEntry = configEntries[0];
|
filteredConfigEntry = configEntries[0];
|
||||||
}
|
}
|
||||||
} else if (key === "ha-filter-integrations" && flter.value?.length) {
|
} else if (key === "ha-filter-integrations" && filter.value?.length) {
|
||||||
const entryIds = entries
|
const entryIds = entries
|
||||||
.filter((entry) => flter.value!.includes(entry.domain))
|
.filter((entry) => filter.value!.includes(entry.domain))
|
||||||
.map((entry) => entry.entry_id);
|
.map((entry) => entry.entry_id);
|
||||||
outputDevices = outputDevices.filter((device) =>
|
outputDevices = outputDevices.filter((device) =>
|
||||||
device.config_entries.some((entryId) => entryIds.includes(entryId))
|
device.config_entries.some((entryId) => entryIds.includes(entryId))
|
||||||
);
|
);
|
||||||
flter.value!.forEach((domain) => filteredDomains.add(domain));
|
filter.value!.forEach((domain) => filteredDomains.add(domain));
|
||||||
} else if (flter.items) {
|
} else if (key === "ha-filter-labels" && filter.value?.length) {
|
||||||
outputDevices = outputDevices.filter((device) =>
|
outputDevices = outputDevices.filter((device) =>
|
||||||
flter.items!.has(device.id)
|
device.labels.some((lbl) => filter.value!.includes(lbl))
|
||||||
|
);
|
||||||
|
} else if (filter.items) {
|
||||||
|
outputDevices = outputDevices.filter((device) =>
|
||||||
|
filter.items!.has(device.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -270,6 +292,12 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
.map((entId) => entryLookup[entId]),
|
.map((entId) => entryLookup[entId]),
|
||||||
manifestLookup
|
manifestLookup
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const labels = labelReg && device?.labels;
|
||||||
|
const labelsEntries = (labels || []).map(
|
||||||
|
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...device,
|
...device,
|
||||||
name: computeDeviceName(
|
name: computeDeviceName(
|
||||||
@ -306,6 +334,7 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
this.hass.states[
|
this.hass.states[
|
||||||
this._batteryEntity(device.id, deviceEntityLookup) || ""
|
this._batteryEntity(device.id, deviceEntityLookup) || ""
|
||||||
]?.state,
|
]?.state,
|
||||||
|
label_entries: labelsEntries,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -351,8 +380,15 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (device) => html`
|
template: (device) => html`
|
||||||
${device.name}
|
<div style="font-size: 14px;">${device.name}</div>
|
||||||
<div class="secondary">${device.area} | ${device.integration}</div>
|
<div class="secondary">${device.area} | ${device.integration}</div>
|
||||||
|
${device.label_entries.length
|
||||||
|
? html`
|
||||||
|
<ha-data-table-labels
|
||||||
|
.labels=${device.label_entries}
|
||||||
|
></ha-data-table-labels>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@ -361,8 +397,18 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
main: true,
|
main: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
|
grows: true,
|
||||||
|
template: (device) => html`
|
||||||
|
<div style="font-size: 14px;">${device.name}</div>
|
||||||
|
${device.label_entries.length
|
||||||
|
? html`
|
||||||
|
<ha-data-table-labels
|
||||||
|
.labels=${device.label_entries}
|
||||||
|
></ha-data-table-labels>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,9 +487,25 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
? this.hass.localize("ui.panel.config.devices.disabled")
|
? this.hass.localize("ui.panel.config.devices.disabled")
|
||||||
: "",
|
: "",
|
||||||
};
|
};
|
||||||
|
columns.labels = {
|
||||||
|
title: "",
|
||||||
|
hidden: true,
|
||||||
|
filterable: true,
|
||||||
|
template: (device) =>
|
||||||
|
device.label_entries.map((lbl) => lbl.name).join(" "),
|
||||||
|
};
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
||||||
|
return [
|
||||||
|
subscribeLabelRegistry(this.hass.connection, (labels) => {
|
||||||
|
this._labels = labels;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const { devicesOutput } = this._devicesAndFilterDomains(
|
const { devicesOutput } = this._devicesAndFilterDomains(
|
||||||
this.hass.devices,
|
this.hass.devices,
|
||||||
@ -452,7 +514,8 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
this.hass.areas,
|
this.hass.areas,
|
||||||
this.manifests,
|
this.manifests,
|
||||||
this._filters,
|
this._filters,
|
||||||
this.hass.localize
|
this.hass.localize,
|
||||||
|
this._labels
|
||||||
);
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@ -479,6 +542,7 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
@row-click=${this._handleRowClicked}
|
@row-click=${this._handleRowClicked}
|
||||||
clickable
|
clickable
|
||||||
hasFab
|
hasFab
|
||||||
|
class=${this.narrow ? "narrow" : ""}
|
||||||
>
|
>
|
||||||
<ha-integration-overflow-menu
|
<ha-integration-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -531,6 +595,15 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
@expanded-changed=${this._filterExpanded}
|
@expanded-changed=${this._filterExpanded}
|
||||||
></ha-filter-states>
|
></ha-filter-states>
|
||||||
|
<ha-filter-labels
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._filters["ha-filter-labels"]?.value}
|
||||||
|
@data-table-filter-changed=${this._filterChanged}
|
||||||
|
slot="filter-pane"
|
||||||
|
.expanded=${this._expandedFilter === "ha-filter-labels"}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
@expanded-changed=${this._filterExpanded}
|
||||||
|
></ha-filter-labels>
|
||||||
</hass-tabs-subpage-data-table>
|
</hass-tabs-subpage-data-table>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -590,8 +663,10 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
this.hass.areas,
|
this.hass.areas,
|
||||||
this.manifests,
|
this.manifests,
|
||||||
this._filters,
|
this._filters,
|
||||||
this.hass.localize
|
this.hass.localize,
|
||||||
|
this._labels
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
filteredDomains.size === 1 &&
|
filteredDomains.size === 1 &&
|
||||||
(PROTOCOL_INTEGRATIONS as ReadonlyArray<string>).includes(
|
(PROTOCOL_INTEGRATIONS as ReadonlyArray<string>).includes(
|
||||||
@ -611,6 +686,12 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
css`
|
css`
|
||||||
|
hass-tabs-subpage-data-table {
|
||||||
|
--data-table-row-height: 60px;
|
||||||
|
}
|
||||||
|
hass-tabs-subpage-data-table.narrow {
|
||||||
|
--data-table-row-height: 72px;
|
||||||
|
}
|
||||||
ha-button-menu {
|
ha-button-menu {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
margin-inline-start: 8px;
|
margin-inline-start: 8px;
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
mdiRestoreAlert,
|
mdiRestoreAlert,
|
||||||
mdiUndo,
|
mdiUndo,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
LitElement,
|
LitElement,
|
||||||
@ -37,16 +37,18 @@ import type {
|
|||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
SelectionChangedEvent,
|
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/ha-alert";
|
||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-check-list-item";
|
import "../../../components/ha-check-list-item";
|
||||||
import "../../../components/ha-filter-devices";
|
import "../../../components/ha-filter-devices";
|
||||||
import "../../../components/ha-filter-floor-areas";
|
import "../../../components/ha-filter-floor-areas";
|
||||||
import "../../../components/ha-filter-integrations";
|
import "../../../components/ha-filter-integrations";
|
||||||
import "../../../components/ha-filter-states";
|
import "../../../components/ha-filter-states";
|
||||||
|
import "../../../components/ha-filter-labels";
|
||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import "../../../components/ha-alert";
|
|
||||||
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
|
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
|
||||||
import { fullEntitiesContext } from "../../../data/context";
|
import { fullEntitiesContext } from "../../../data/context";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
@ -57,6 +59,10 @@ import {
|
|||||||
updateEntityRegistryEntry,
|
updateEntityRegistryEntry,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import { entryIcon } from "../../../data/icons";
|
import { entryIcon } from "../../../data/icons";
|
||||||
|
import {
|
||||||
|
LabelRegistryEntry,
|
||||||
|
subscribeLabelRegistry,
|
||||||
|
} from "../../../data/label_registry";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@ -65,6 +71,7 @@ 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 type { HaTabsSubpageDataTable } from "../../../layouts/hass-tabs-subpage-data-table";
|
import type { HaTabsSubpageDataTable } from "../../../layouts/hass-tabs-subpage-data-table";
|
||||||
|
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import type { HomeAssistant, Route } from "../../../types";
|
import type { HomeAssistant, Route } from "../../../types";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
@ -86,10 +93,11 @@ export interface EntityRow extends StateEntity {
|
|||||||
status: string | undefined;
|
status: string | undefined;
|
||||||
area?: string;
|
area?: string;
|
||||||
localized_platform: string;
|
localized_platform: string;
|
||||||
|
label_entries: LabelRegistryEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("ha-config-entities")
|
@customElement("ha-config-entities")
|
||||||
export class HaConfigEntities extends LitElement {
|
export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ type: Boolean }) public isWide = false;
|
@property({ type: Boolean }) public isWide = false;
|
||||||
@ -119,6 +127,9 @@ export class HaConfigEntities extends LitElement {
|
|||||||
|
|
||||||
@state() private _expandedFilter?: string;
|
@state() private _expandedFilter?: string;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_labels!: LabelRegistryEntry[];
|
||||||
|
|
||||||
@query("hass-tabs-subpage-data-table", true)
|
@query("hass-tabs-subpage-data-table", true)
|
||||||
private _dataTable!: HaTabsSubpageDataTable;
|
private _dataTable!: HaTabsSubpageDataTable;
|
||||||
|
|
||||||
@ -202,14 +213,21 @@ export class HaConfigEntities extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: narrow
|
template: (entry) => html`
|
||||||
? (entry) => html`
|
<div style="font-size: 14px;">${entry.name}</div>
|
||||||
${entry.name}<br />
|
${narrow
|
||||||
<div class="secondary">
|
? html`<div class="secondary">
|
||||||
${entry.entity_id} | ${entry.localized_platform}
|
${entry.entity_id} | ${entry.localized_platform}
|
||||||
</div>
|
</div>`
|
||||||
`
|
: nothing}
|
||||||
: undefined,
|
${entry.label_entries.length
|
||||||
|
? html`
|
||||||
|
<ha-data-table-labels
|
||||||
|
.labels=${entry.label_entries}
|
||||||
|
></ha-data-table-labels>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
`,
|
||||||
},
|
},
|
||||||
entity_id: {
|
entity_id: {
|
||||||
title: localize("ui.panel.config.entities.picker.headers.entity_id"),
|
title: localize("ui.panel.config.entities.picker.headers.entity_id"),
|
||||||
@ -301,6 +319,13 @@ export class HaConfigEntities extends LitElement {
|
|||||||
`
|
`
|
||||||
: "—",
|
: "—",
|
||||||
},
|
},
|
||||||
|
labels: {
|
||||||
|
title: "",
|
||||||
|
hidden: true,
|
||||||
|
filterable: true,
|
||||||
|
template: (entry) =>
|
||||||
|
entry.label_entries.map((lbl) => lbl.name).join(" "),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -315,7 +340,8 @@ export class HaConfigEntities extends LitElement {
|
|||||||
string,
|
string,
|
||||||
{ value: string[] | undefined; items: Set<string> | undefined }
|
{ value: string[] | undefined; items: Set<string> | undefined }
|
||||||
>,
|
>,
|
||||||
entries?: ConfigEntry[]
|
entries?: ConfigEntry[],
|
||||||
|
labelReg?: LabelRegistryEntry[]
|
||||||
) => {
|
) => {
|
||||||
const result: EntityRow[] = [];
|
const result: EntityRow[] = [];
|
||||||
|
|
||||||
@ -337,12 +363,12 @@ export class HaConfigEntities extends LitElement {
|
|||||||
let filteredConfigEntry: ConfigEntry | undefined;
|
let filteredConfigEntry: ConfigEntry | undefined;
|
||||||
const filteredDomains = new Set<string>();
|
const filteredDomains = new Set<string>();
|
||||||
|
|
||||||
Object.entries(filters).forEach(([key, flter]) => {
|
Object.entries(filters).forEach(([key, filter]) => {
|
||||||
if (key === "config_entry" && flter.value?.length) {
|
if (key === "config_entry" && filter.value?.length) {
|
||||||
filteredEntities = filteredEntities.filter(
|
filteredEntities = filteredEntities.filter(
|
||||||
(entity) =>
|
(entity) =>
|
||||||
entity.config_entry_id &&
|
entity.config_entry_id &&
|
||||||
flter.value?.includes(entity.config_entry_id)
|
filter.value?.includes(entity.config_entry_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!entries) {
|
if (!entries) {
|
||||||
@ -351,7 +377,7 @@ export class HaConfigEntities extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const configEntries = entries.filter(
|
const configEntries = entries.filter(
|
||||||
(entry) => entry.entry_id && flter.value?.includes(entry.entry_id)
|
(entry) => entry.entry_id && filter.value?.includes(entry.entry_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
configEntries.forEach((configEntry) => {
|
configEntries.forEach((configEntry) => {
|
||||||
@ -360,23 +386,27 @@ export class HaConfigEntities extends LitElement {
|
|||||||
if (configEntries.length === 1) {
|
if (configEntries.length === 1) {
|
||||||
filteredConfigEntry = configEntries[0];
|
filteredConfigEntry = configEntries[0];
|
||||||
}
|
}
|
||||||
} else if (key === "ha-filter-integrations" && flter.value?.length) {
|
} else if (key === "ha-filter-integrations" && filter.value?.length) {
|
||||||
if (!entries) {
|
if (!entries) {
|
||||||
this._loadConfigEntries();
|
this._loadConfigEntries();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const entryIds = entries
|
const entryIds = entries
|
||||||
.filter((entry) => flter.value!.includes(entry.domain))
|
.filter((entry) => filter.value!.includes(entry.domain))
|
||||||
.map((entry) => entry.entry_id);
|
.map((entry) => entry.entry_id);
|
||||||
filteredEntities = filteredEntities.filter(
|
filteredEntities = filteredEntities.filter(
|
||||||
(entity) =>
|
(entity) =>
|
||||||
entity.config_entry_id &&
|
entity.config_entry_id &&
|
||||||
entryIds.includes(entity.config_entry_id)
|
entryIds.includes(entity.config_entry_id)
|
||||||
);
|
);
|
||||||
flter.value!.forEach((domain) => filteredDomains.add(domain));
|
filter.value!.forEach((domain) => filteredDomains.add(domain));
|
||||||
} else if (flter.items) {
|
} else if (key === "ha-filter-labels" && filter.value?.length) {
|
||||||
filteredEntities = filteredEntities.filter((entity) =>
|
filteredEntities = filteredEntities.filter((entity) =>
|
||||||
flter.items!.has(entity.entity_id)
|
entity.labels.some((lbl) => filter.value!.includes(lbl))
|
||||||
|
);
|
||||||
|
} else if (filter.items) {
|
||||||
|
filteredEntities = filteredEntities.filter((entity) =>
|
||||||
|
filter.items!.has(entity.entity_id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -404,6 +434,11 @@ export class HaConfigEntities extends LitElement {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const labels = labelReg && entry?.labels;
|
||||||
|
const labelsEntries = (labels || []).map(
|
||||||
|
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||||
|
);
|
||||||
|
|
||||||
result.push({
|
result.push({
|
||||||
...entry,
|
...entry,
|
||||||
entity,
|
entity,
|
||||||
@ -431,6 +466,7 @@ export class HaConfigEntities extends LitElement {
|
|||||||
: localize(
|
: localize(
|
||||||
"ui.panel.config.entities.picker.status.available"
|
"ui.panel.config.entities.picker.status.available"
|
||||||
),
|
),
|
||||||
|
label_entries: labelsEntries,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,6 +474,14 @@ export class HaConfigEntities extends LitElement {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
||||||
|
return [
|
||||||
|
subscribeLabelRegistry(this.hass.connection, (labels) => {
|
||||||
|
this._labels = labels;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this.hass || this._entities === undefined) {
|
if (!this.hass || this._entities === undefined) {
|
||||||
return html` <hass-loading-screen></hass-loading-screen> `;
|
return html` <hass-loading-screen></hass-loading-screen> `;
|
||||||
@ -451,7 +495,8 @@ export class HaConfigEntities extends LitElement {
|
|||||||
this.hass.areas,
|
this.hass.areas,
|
||||||
this._stateEntities,
|
this._stateEntities,
|
||||||
this._filters,
|
this._filters,
|
||||||
this._entries
|
this._entries,
|
||||||
|
this._labels
|
||||||
);
|
);
|
||||||
|
|
||||||
const includeAddDeviceFab =
|
const includeAddDeviceFab =
|
||||||
@ -492,6 +537,7 @@ export class HaConfigEntities extends LitElement {
|
|||||||
@row-click=${this._openEditEntry}
|
@row-click=${this._openEditEntry}
|
||||||
id="entity_id"
|
id="entity_id"
|
||||||
.hasFab=${includeAddDeviceFab}
|
.hasFab=${includeAddDeviceFab}
|
||||||
|
class=${this.narrow ? "narrow" : ""}
|
||||||
>
|
>
|
||||||
<ha-integration-overflow-menu
|
<ha-integration-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -633,6 +679,15 @@ export class HaConfigEntities extends LitElement {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
@expanded-changed=${this._filterExpanded}
|
@expanded-changed=${this._filterExpanded}
|
||||||
></ha-filter-states>
|
></ha-filter-states>
|
||||||
|
<ha-filter-labels
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._filters["ha-filter-labels"]?.value}
|
||||||
|
@data-table-filter-changed=${this._filterChanged}
|
||||||
|
slot="filter-pane"
|
||||||
|
.expanded=${this._expandedFilter === "ha-filter-labels"}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
@expanded-changed=${this._filterExpanded}
|
||||||
|
></ha-filter-labels>
|
||||||
${includeAddDeviceFab
|
${includeAddDeviceFab
|
||||||
? html`<ha-fab
|
? html`<ha-fab
|
||||||
.label=${this.hass.localize("ui.panel.config.devices.add_device")}
|
.label=${this.hass.localize("ui.panel.config.devices.add_device")}
|
||||||
@ -918,7 +973,8 @@ export class HaConfigEntities extends LitElement {
|
|||||||
this.hass.areas,
|
this.hass.areas,
|
||||||
this._stateEntities,
|
this._stateEntities,
|
||||||
this._filters,
|
this._filters,
|
||||||
this._entries
|
this._entries,
|
||||||
|
this._labels
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
filteredDomains.size === 1 &&
|
filteredDomains.size === 1 &&
|
||||||
@ -940,6 +996,12 @@ export class HaConfigEntities extends LitElement {
|
|||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
hass-tabs-subpage-data-table {
|
||||||
|
--data-table-row-height: 60px;
|
||||||
|
}
|
||||||
|
hass-tabs-subpage-data-table.narrow {
|
||||||
|
--data-table-row-height: 72px;
|
||||||
|
}
|
||||||
hass-loading-screen {
|
hass-loading-screen {
|
||||||
--app-header-background-color: var(--sidebar-background-color);
|
--app-header-background-color: var(--sidebar-background-color);
|
||||||
--app-header-text-color: var(--sidebar-text-color);
|
--app-header-text-color: var(--sidebar-text-color);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mdiHelpCircle, mdiPlus } from "@mdi/js";
|
import { mdiDelete, mdiHelpCircle, mdiPlus } from "@mdi/js";
|
||||||
import { LitElement, PropertyValues, html, nothing } from "lit";
|
import { LitElement, PropertyValues, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
@ -11,6 +11,7 @@ import {
|
|||||||
import "../../../components/ha-fab";
|
import "../../../components/ha-fab";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-relative-time";
|
import "../../../components/ha-relative-time";
|
||||||
|
import "../../../components/ha-icon-overflow-menu";
|
||||||
import {
|
import {
|
||||||
LabelRegistryEntry,
|
LabelRegistryEntry,
|
||||||
LabelRegistryEntryMutableParams,
|
LabelRegistryEntryMutableParams,
|
||||||
@ -71,6 +72,26 @@ export class HaConfigLabels extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
},
|
},
|
||||||
|
actions: {
|
||||||
|
title: "",
|
||||||
|
width: "64px",
|
||||||
|
type: "overflow-menu",
|
||||||
|
template: (label) => html`
|
||||||
|
<ha-icon-overflow-menu
|
||||||
|
.hass=${this.hass}
|
||||||
|
narrow
|
||||||
|
.items=${[
|
||||||
|
{
|
||||||
|
label: this.hass.localize("ui.common.delete"),
|
||||||
|
path: mdiDelete,
|
||||||
|
action: () => this._removeLabel(label),
|
||||||
|
warning: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
</ha-icon-overflow-menu>
|
||||||
|
`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return columns;
|
return columns;
|
||||||
});
|
});
|
||||||
@ -189,6 +210,7 @@ export class HaConfigLabels extends LitElement {
|
|||||||
}),
|
}),
|
||||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
dismissText: this.hass!.localize("ui.common.cancel"),
|
||||||
confirmText: this.hass!.localize("ui.common.remove"),
|
confirmText: this.hass!.localize("ui.common.remove"),
|
||||||
|
destructive: true,
|
||||||
}))
|
}))
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -16,6 +16,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
|||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
css,
|
css,
|
||||||
html,
|
html,
|
||||||
@ -297,6 +298,13 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (changedProps.has("_entityReg")) {
|
||||||
|
this._applyFilters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
||||||
return [
|
return [
|
||||||
subscribeCategoryRegistry(this.hass.connection, "scene", (categories) => {
|
subscribeCategoryRegistry(this.hass.connection, "scene", (categories) => {
|
||||||
|
@ -15,6 +15,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
|||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
css,
|
css,
|
||||||
html,
|
html,
|
||||||
@ -560,6 +561,13 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
|||||||
this._filteredScripts = items ? [...items] : undefined;
|
this._filteredScripts = items ? [...items] : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (changedProps.has("_entityReg")) {
|
||||||
|
this._applyFilters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
if (this._searchParms.has("blueprint")) {
|
if (this._searchParms.has("blueprint")) {
|
||||||
this._filterBlueprint();
|
this._filterBlueprint();
|
||||||
|
@ -98,10 +98,10 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
|||||||
display: block;
|
display: block;
|
||||||
padding: 24px 16px 16px;
|
padding: 24px 16px 16px;
|
||||||
}
|
}
|
||||||
:host {
|
#root {
|
||||||
--ha-card-border-radius: inherit !important;
|
--ha-card-border-radius: var(--restore-card-border-radius, inherit);
|
||||||
--ha-card-border-width: inherit !important;
|
--ha-card-border-width: var(--restore-card-border-width, inherit);
|
||||||
--ha-card-box-shadow: inherit !important;
|
--ha-card-box-shadow: var(--restore-card-border-shadow, inherit);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,7 @@ export class PanelView extends LitElement implements LovelaceViewElement {
|
|||||||
|
|
||||||
const card: LovelaceCard = this.cards[0];
|
const card: LovelaceCard = this.cards[0];
|
||||||
card.isPanel = true;
|
card.isPanel = true;
|
||||||
|
card.toggleAttribute("no-border", true);
|
||||||
|
|
||||||
if (this.isStrategy || !this.lovelace?.editMode) {
|
if (this.isStrategy || !this.lovelace?.editMode) {
|
||||||
card.editMode = false;
|
card.editMode = false;
|
||||||
@ -116,6 +117,7 @@ export class PanelView extends LitElement implements LovelaceViewElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const wrapper = document.createElement("hui-card-options");
|
const wrapper = document.createElement("hui-card-options");
|
||||||
|
wrapper.toggleAttribute("no-border", true);
|
||||||
wrapper.hass = this.hass;
|
wrapper.hass = this.hass;
|
||||||
wrapper.lovelace = this.lovelace;
|
wrapper.lovelace = this.lovelace;
|
||||||
wrapper.path = [this.index!, 0];
|
wrapper.path = [this.index!, 0];
|
||||||
@ -130,9 +132,12 @@ export class PanelView extends LitElement implements LovelaceViewElement {
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
--restore-card-border-radius: var(--ha-card-border-radius, 12px);
|
||||||
|
--restore-card-border-width: var(--ha-card-border-width, 1px);
|
||||||
|
--restore-card-box-shadow: var(--ha-card-box-shadow, none);
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
[no-border] {
|
||||||
--ha-card-border-radius: 0;
|
--ha-card-border-radius: 0;
|
||||||
--ha-card-border-width: 0;
|
--ha-card-border-width: 0;
|
||||||
--ha-card-box-shadow: none;
|
--ha-card-box-shadow: none;
|
||||||
|
@ -32,6 +32,7 @@ const mainStyles = css`
|
|||||||
--accent-color: ${unsafeCSS(DEFAULT_ACCENT_COLOR)};
|
--accent-color: ${unsafeCSS(DEFAULT_ACCENT_COLOR)};
|
||||||
--divider-color: rgba(0, 0, 0, 0.12);
|
--divider-color: rgba(0, 0, 0, 0.12);
|
||||||
--outline-color: rgba(0, 0, 0, 0.12);
|
--outline-color: rgba(0, 0, 0, 0.12);
|
||||||
|
--outline-hover-color: rgba(0, 0, 0, 0.24);
|
||||||
|
|
||||||
--scrollbar-thumb-color: rgb(194, 194, 194);
|
--scrollbar-thumb-color: rgb(194, 194, 194);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ export const darkStyles = {
|
|||||||
"switch-unchecked-track-color": "#9b9b9b",
|
"switch-unchecked-track-color": "#9b9b9b",
|
||||||
"divider-color": "rgba(225, 225, 225, .12)",
|
"divider-color": "rgba(225, 225, 225, .12)",
|
||||||
"outline-color": "rgba(225, 225, 225, .12)",
|
"outline-color": "rgba(225, 225, 225, .12)",
|
||||||
|
"outline-hover-color": "rgba(225, 225, 225, .24)",
|
||||||
"mdc-ripple-color": "#AAAAAA",
|
"mdc-ripple-color": "#AAAAAA",
|
||||||
"mdc-linear-progress-buffer-color": "rgba(255, 255, 255, 0.1)",
|
"mdc-linear-progress-buffer-color": "rgba(255, 255, 255, 0.1)",
|
||||||
|
|
||||||
|
@ -1959,7 +1959,11 @@
|
|||||||
"labels": {
|
"labels": {
|
||||||
"caption": "Labels",
|
"caption": "Labels",
|
||||||
"description": "Group devices and entities",
|
"description": "Group devices and entities",
|
||||||
"headers": { "name": "Name", "icon": "Icon", "color": "Color" },
|
"headers": {
|
||||||
|
"name": "Name",
|
||||||
|
"icon": "Icon",
|
||||||
|
"color": "Color"
|
||||||
|
},
|
||||||
"add_label": "Add label",
|
"add_label": "Add label",
|
||||||
"no_labels": "You don't have any labels",
|
"no_labels": "You don't have any labels",
|
||||||
"introduction": "Labels can help you organize your areas, devices and entities. They can be used to filter in the UI, or use them as a target in automations.",
|
"introduction": "Labels can help you organize your areas, devices and entities. They can be used to filter in the UI, or use them as a target in automations.",
|
||||||
@ -5388,7 +5392,6 @@
|
|||||||
"type": "View type",
|
"type": "View type",
|
||||||
"type_warning_sections": "You can not change your view to use the 'sections' view type because migration is not supported yet. Start from scratch with a new view if you want to experiment with the 'sections' view.",
|
"type_warning_sections": "You can not change your view to use the 'sections' view type because migration is not supported yet. Start from scratch with a new view if you want to experiment with the 'sections' view.",
|
||||||
"type_warning_others": "You can not change your view to an other type because migration is not supported yet. Start from scratch with a new view if you want to use another view type.",
|
"type_warning_others": "You can not change your view to an other type because migration is not supported yet. Start from scratch with a new view if you want to use another view type.",
|
||||||
|
|
||||||
"types": {
|
"types": {
|
||||||
"masonry": "Masonry (default)",
|
"masonry": "Masonry (default)",
|
||||||
"sidebar": "Sidebar",
|
"sidebar": "Sidebar",
|
||||||
|
104
yarn.lock
104
yarn.lock
@ -4543,15 +4543,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@npm:7.3.1":
|
"@typescript-eslint/eslint-plugin@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/eslint-plugin@npm:7.3.1"
|
resolution: "@typescript-eslint/eslint-plugin@npm:7.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/regexpp": "npm:^4.5.1"
|
"@eslint-community/regexpp": "npm:^4.5.1"
|
||||||
"@typescript-eslint/scope-manager": "npm:7.3.1"
|
"@typescript-eslint/scope-manager": "npm:7.4.0"
|
||||||
"@typescript-eslint/type-utils": "npm:7.3.1"
|
"@typescript-eslint/type-utils": "npm:7.4.0"
|
||||||
"@typescript-eslint/utils": "npm:7.3.1"
|
"@typescript-eslint/utils": "npm:7.4.0"
|
||||||
"@typescript-eslint/visitor-keys": "npm:7.3.1"
|
"@typescript-eslint/visitor-keys": "npm:7.4.0"
|
||||||
debug: "npm:^4.3.4"
|
debug: "npm:^4.3.4"
|
||||||
graphemer: "npm:^1.4.0"
|
graphemer: "npm:^1.4.0"
|
||||||
ignore: "npm:^5.2.4"
|
ignore: "npm:^5.2.4"
|
||||||
@ -4564,44 +4564,44 @@ __metadata:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10/8ed276113a714d93ab3ababb1179e4785bd9378e6d97726519ea1d2ac502a94475e0be988c2ec427dcfc1e6950329d58da6e64131ee87028fce63493461cc51a
|
checksum: 10/9bd8852c7e4e9608c3fded94f7c60506cc7d2b6d8a8c1cad6d48969a7363751b20282874e55ccdf180635cf204cb10b3e1e5c3d1cff34d4fcd07762be3fc138e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/parser@npm:7.3.1":
|
"@typescript-eslint/parser@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/parser@npm:7.3.1"
|
resolution: "@typescript-eslint/parser@npm:7.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/scope-manager": "npm:7.3.1"
|
"@typescript-eslint/scope-manager": "npm:7.4.0"
|
||||||
"@typescript-eslint/types": "npm:7.3.1"
|
"@typescript-eslint/types": "npm:7.4.0"
|
||||||
"@typescript-eslint/typescript-estree": "npm:7.3.1"
|
"@typescript-eslint/typescript-estree": "npm:7.4.0"
|
||||||
"@typescript-eslint/visitor-keys": "npm:7.3.1"
|
"@typescript-eslint/visitor-keys": "npm:7.4.0"
|
||||||
debug: "npm:^4.3.4"
|
debug: "npm:^4.3.4"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.56.0
|
eslint: ^8.56.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10/018326010fec1dcefd75809ccac5102a475bf1e052d824b898d707e7c0bf3e51e101164b410d1b2a513628985c96eb412538644d2005e26b99a22db6eb9402df
|
checksum: 10/142a9e1187d305ed43b4fef659c36fa4e28359467198c986f0955c70b4067c9799f4c85d9881fbf099c55dfb265e30666e28b3ef290520e242b45ca7cb8e4ca9
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@npm:7.3.1":
|
"@typescript-eslint/scope-manager@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/scope-manager@npm:7.3.1"
|
resolution: "@typescript-eslint/scope-manager@npm:7.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types": "npm:7.3.1"
|
"@typescript-eslint/types": "npm:7.4.0"
|
||||||
"@typescript-eslint/visitor-keys": "npm:7.3.1"
|
"@typescript-eslint/visitor-keys": "npm:7.4.0"
|
||||||
checksum: 10/7384d1f46d7f3678a1135a1ac0bd8b6dfa2f01e93b19e2510c7082766cf6983a1bf80b4ccf498651199a81d9f2bdb65101fd7a19226a723260514204d0c30b34
|
checksum: 10/8cf9292444f9731017a707cac34bef5ae0eb33b5cd42ed07fcd046e981d97889d9201d48e02f470f2315123f53771435e10b1dc81642af28a11df5352a8e8be2
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@npm:7.3.1":
|
"@typescript-eslint/type-utils@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/type-utils@npm:7.3.1"
|
resolution: "@typescript-eslint/type-utils@npm:7.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/typescript-estree": "npm:7.3.1"
|
"@typescript-eslint/typescript-estree": "npm:7.4.0"
|
||||||
"@typescript-eslint/utils": "npm:7.3.1"
|
"@typescript-eslint/utils": "npm:7.4.0"
|
||||||
debug: "npm:^4.3.4"
|
debug: "npm:^4.3.4"
|
||||||
ts-api-utils: "npm:^1.0.1"
|
ts-api-utils: "npm:^1.0.1"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -4609,23 +4609,23 @@ __metadata:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10/fae9003a76a8f2a2a4bb88dc0f82c0a1ca0688633183fac391920e7124a12807aac84bb287a21f61e99523c15223d1c08e7680685ebf21d07429604cba6c420b
|
checksum: 10/a8bd0929d8237679b2b8a7817f070a4b9658ee976882fba8ff37e4a70dd33f87793e1b157771104111fe8054eaa8ad437a010b6aa465072fbdb932647125db2d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/types@npm:7.3.1":
|
"@typescript-eslint/types@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/types@npm:7.3.1"
|
resolution: "@typescript-eslint/types@npm:7.4.0"
|
||||||
checksum: 10/c9c8eae1cf937cececd99a253bd65eb71b40206e79cf917ad9c3b3ab80cc7ce5fefb2804f9fd2a70e7438951f0d1e63df3031fc61e3a08dfef5fde208a12e0ed
|
checksum: 10/2782c5bf65cd3dfa9cd32bc3023676bbca22144987c3f6c6b67fd96c73d4a60b85a57458c49fd11b9971ac6531824bb3ae0664491e7a6de25d80c523c9be92b7
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@npm:7.3.1":
|
"@typescript-eslint/typescript-estree@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/typescript-estree@npm:7.3.1"
|
resolution: "@typescript-eslint/typescript-estree@npm:7.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types": "npm:7.3.1"
|
"@typescript-eslint/types": "npm:7.4.0"
|
||||||
"@typescript-eslint/visitor-keys": "npm:7.3.1"
|
"@typescript-eslint/visitor-keys": "npm:7.4.0"
|
||||||
debug: "npm:^4.3.4"
|
debug: "npm:^4.3.4"
|
||||||
globby: "npm:^11.1.0"
|
globby: "npm:^11.1.0"
|
||||||
is-glob: "npm:^4.0.3"
|
is-glob: "npm:^4.0.3"
|
||||||
@ -4635,34 +4635,34 @@ __metadata:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10/363ad9864b56394b4000dff7c2b77d0ea52042c3c20e3b86c0f3c66044915632d9890255527c6f3a5ef056886dec72e38fbcfce49d4ad092c160440f54128230
|
checksum: 10/162ec9d7582f45588342e1be36fdb60e41f50bbdfbc3035c91b517ff5d45244f776921c88d88e543e1c7d0f1e6ada5474a8316b78f1b0e6d2233b101bc45b166
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/utils@npm:7.3.1":
|
"@typescript-eslint/utils@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/utils@npm:7.3.1"
|
resolution: "@typescript-eslint/utils@npm:7.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils": "npm:^4.4.0"
|
"@eslint-community/eslint-utils": "npm:^4.4.0"
|
||||||
"@types/json-schema": "npm:^7.0.12"
|
"@types/json-schema": "npm:^7.0.12"
|
||||||
"@types/semver": "npm:^7.5.0"
|
"@types/semver": "npm:^7.5.0"
|
||||||
"@typescript-eslint/scope-manager": "npm:7.3.1"
|
"@typescript-eslint/scope-manager": "npm:7.4.0"
|
||||||
"@typescript-eslint/types": "npm:7.3.1"
|
"@typescript-eslint/types": "npm:7.4.0"
|
||||||
"@typescript-eslint/typescript-estree": "npm:7.3.1"
|
"@typescript-eslint/typescript-estree": "npm:7.4.0"
|
||||||
semver: "npm:^7.5.4"
|
semver: "npm:^7.5.4"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.56.0
|
eslint: ^8.56.0
|
||||||
checksum: 10/234d9d65fe5d0f4a31345bd8f5a6f2879a578b3a531a14c2b3edaa7fb587c71d26249f86c41857382c0405384dc104955c02b588b3cee6fc2734f1ae40aef07b
|
checksum: 10/ffed27e770c486cd000ff892d9049b0afe8b9d6318452a5355b78a37436cbb414bceacae413a2ac813f3e584684825d5e0baa2e6376b7ad6013a108ac91bc19d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@npm:7.3.1":
|
"@typescript-eslint/visitor-keys@npm:7.4.0":
|
||||||
version: 7.3.1
|
version: 7.4.0
|
||||||
resolution: "@typescript-eslint/visitor-keys@npm:7.3.1"
|
resolution: "@typescript-eslint/visitor-keys@npm:7.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types": "npm:7.3.1"
|
"@typescript-eslint/types": "npm:7.4.0"
|
||||||
eslint-visitor-keys: "npm:^3.4.1"
|
eslint-visitor-keys: "npm:^3.4.1"
|
||||||
checksum: 10/163a93597c1d696920a19b3c1627d02368bdd52059f811c0fadd680c38034bb6418ebefe99d8ce26e0dd44ae184f18fab186af775de1a8771256be1a7905c174
|
checksum: 10/70dc99f2ad116c6e2d9e55af249e4453e06bba2ceea515adef2d2e86e97e557865bb1b1d467667462443eb0d624baba36f7442fd1082f3874339bbc381c26e93
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -9688,8 +9688,8 @@ __metadata:
|
|||||||
"@types/tar": "npm:6.1.11"
|
"@types/tar": "npm:6.1.11"
|
||||||
"@types/ua-parser-js": "npm:0.7.39"
|
"@types/ua-parser-js": "npm:0.7.39"
|
||||||
"@types/webspeechapi": "npm:0.0.29"
|
"@types/webspeechapi": "npm:0.0.29"
|
||||||
"@typescript-eslint/eslint-plugin": "npm:7.3.1"
|
"@typescript-eslint/eslint-plugin": "npm:7.4.0"
|
||||||
"@typescript-eslint/parser": "npm:7.3.1"
|
"@typescript-eslint/parser": "npm:7.4.0"
|
||||||
"@vaadin/combo-box": "npm:24.3.10"
|
"@vaadin/combo-box": "npm:24.3.10"
|
||||||
"@vaadin/vaadin-themable-mixin": "npm:24.3.10"
|
"@vaadin/vaadin-themable-mixin": "npm:24.3.10"
|
||||||
"@vibrant/color": "npm:3.2.1-alpha.1"
|
"@vibrant/color": "npm:3.2.1-alpha.1"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user