Compare commits

...

42 Commits

Author SHA1 Message Date
Paul Bottein
c3f0bba4a3 20250701.0 (#26019) 2025-07-01 15:04:35 +02:00
Paul Bottein
0026ee7563 Bumped version to 20250701.0 2025-07-01 15:02:51 +02:00
Paul Bottein
61f1c8cbd4 Force narrow style for action, condition and trigger in blueprint (#26018) 2025-07-01 15:02:17 +02:00
Paul Bottein
e0b32ea789 Increase target area in tile card and area card (#26017) 2025-07-01 15:02:17 +02:00
Paul Bottein
96bbfe8a93 Add dashboard title to strategy editor (#26015) 2025-07-01 15:02:16 +02:00
Paul Bottein
93837f01f7 Avoid selector to take to much space in action calls (#26014) 2025-07-01 15:02:15 +02:00
Ezra Freedman
d0737082a5 Fix translation in the integration page for entities (#26009)
add call to localize
2025-07-01 15:02:14 +02:00
Paul Bottein
57da4d3499 Fix object selector not displayed (#26007) 2025-07-01 15:02:13 +02:00
Paul Bottein
6e84fee791 Do not display quality scale for custom integrations (#26006) 2025-07-01 15:02:12 +02:00
Paul Bottein
2e223e637b Improve device row in integration page (#26005)
Improve device row in config entry page
2025-07-01 15:02:11 +02:00
Paul Bottein
3e45821fd0 Allow to re-order floors in areas dashboard (#26002)
* Allow to re-order floors in areas dashboard

* Move drag handle to right

* Improve typings

* Only show drag handle if there is at least 2 floors
2025-07-01 15:02:10 +02:00
Simon Lamon
b16087d5b5 Fix fullscreen yaml editor (transparency background) (#25989)
Fix fullscreen editor (transparency background)
2025-07-01 15:02:10 +02:00
Norbert Rittel
6300bfb200 Fix grammar of Light, Sensor and Tile card descriptions (#25988)
* Fix grammar of Light, Sensor and Entity card descriptions

* Capitalize "Tile card" as a name

* Apply same change to Entity badge description
2025-07-01 15:02:09 +02:00
Simon Lamon
05a9f69c9e Pass area control service calls through hass (#25986)
Connection logging
2025-07-01 15:02:08 +02:00
Norbert Rittel
e306e29d95 Fix sentence-casing, spelling and grammar issues (#25981)
* Fix sentence-casing, spelling and grammar issues

* Add "IP information" to the list

* More sentence-casing issues
2025-07-01 15:02:07 +02:00
Norbert Rittel
619974ffdb Dev Tools: Remove excessive space from "Input date times" (#25973)
Remove excessive space from "input date times"
2025-07-01 15:02:06 +02:00
Paul Bottein
6f753c4909 Use entity format state if only one entity for that domain in the area card (#25964)
Use entity format state if only one entity is area card
2025-07-01 15:02:05 +02:00
Paul Bottein
a0a2b5f065 20250627.0 (#25971) 2025-06-27 13:51:57 +02:00
Paul Bottein
5430325127 Bumped version to 20250627.0 2025-06-27 13:50:14 +02:00
Paul Bottein
56d3cf7f1e Use areas dashboard name in the top bar (#25969) 2025-06-27 13:49:10 +02:00
Paul Bottein
b39e9c38b9 Bump vaadin to 24.7.9 (#25963) 2025-06-27 13:49:09 +02:00
Bram Kragten
c065efc52f Disable fullscreen editor for editors that are already fullscreen (#25959)
* Disabled fullscreen editor for editors that are already fullscreen

* Update ha-code-editor.ts
2025-06-27 13:49:08 +02:00
Paul Bottein
caaec7d34d Fix expand icon for entries and sub entries (#25955) 2025-06-27 13:49:07 +02:00
Bram Kragten
76509d8bd4 Bumped version to 20250626.0 2025-06-26 16:44:40 +02:00
Paul Bottein
11fcab87d4 Revert vaadin to 24.7.7 (#25953) 2025-06-26 16:44:05 +02:00
Paul Bottein
bfa0b8c0fc Don't limit combo-box dropdown size (#25952) 2025-06-26 16:44:04 +02:00
Bram Kragten
f54312a7bc Load title when fetching flow (#25951) 2025-06-26 16:44:03 +02:00
Bram Kragten
8ff3f7733f Fix filtering on device in entities config panel (#25948)
* Fix filtering on device in entities config panel

* fix

* set filters from url twice to catch race...
2025-06-26 16:44:02 +02:00
Paul Bottein
def8e8a713 Disable escape key to close edit card dialog (#25947) 2025-06-26 16:44:01 +02:00
Bram Kragten
e675283fcc Add label to version number (#25942)
Add label
2025-06-26 16:44:00 +02:00
Bram Kragten
1900cce7f9 make sure header is always shown in data entry flow (#25941) 2025-06-26 16:44:00 +02:00
Bram Kragten
8e2c943dff add version number to integration page (#25940)
* add version number to integration page

* Update ha-config-integration-page.ts
2025-06-26 16:43:59 +02:00
Bram Kragten
8c5beb724f Use different icon for services (#25939) 2025-06-26 16:43:58 +02:00
Paul Bottein
b9fb981fb2 Remove alert classes and only use slot sensors for areas dashboard (#25937)
* Remove alert classes and only used slot sensors for areas dashboard

* Rename group to sensors

* Rename group to sensors
2025-06-26 16:43:57 +02:00
Paul Bottein
3456aa96e8 Better handle case when no floors in areas dashboard (#25933) 2025-06-26 16:43:56 +02:00
Eric Stern
e88d9a1ffb Fix logbook stream subscription (#25927) 2025-06-26 16:43:56 +02:00
Paulus Schoutsen
0b488e1ffd Fix wrapping of add subentry buttons (#25925) 2025-06-26 16:43:55 +02:00
Paulus Schoutsen
47aea824aa Make the config entry row section wider on mobile (#25924) 2025-06-26 16:43:54 +02:00
Bram Kragten
570c63c50a Prevent overflow of ripple on device row on integration page (#25922) 2025-06-26 16:43:53 +02:00
Bram Kragten
d9a3a27245 Dont show internal quality scale (#25921)
dont show internal quality scale
2025-06-26 16:43:52 +02:00
Bram Kragten
3d1a3e2335 Only show own devices when there are devices... (#25920)
only show own devices when there are devices...
2025-06-26 16:43:51 +02:00
Bram Kragten
42815c4d5e Update confirm disable messages (#25919) 2025-06-26 16:43:50 +02:00
48 changed files with 775 additions and 580 deletions

View File

@@ -89,8 +89,8 @@
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "3.8.1",
"@tsparticles/preset-links": "3.2.0",
"@vaadin/combo-box": "24.8.0",
"@vaadin/vaadin-themable-mixin": "24.8.0",
"@vaadin/combo-box": "24.7.9",
"@vaadin/vaadin-themable-mixin": "24.7.9",
"@vibrant/color": "4.0.0",
"@vue/web-component-wrapper": "1.3.0",
"@webcomponents/scoped-custom-element-registry": "0.0.10",

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20250625.0"
version = "20250701.0"
license = "Apache-2.0"
license-files = ["LICENSE*"]
description = "The Home Assistant frontend"

View File

@@ -202,7 +202,6 @@ export function storage(options: {
// Don't set the initial value if we have a value in localStorage
if (this.__initialized || getValue() === undefined) {
setValue(this, value);
this.requestUpdate(propertyKey, undefined);
}
},
configurable: true,
@@ -212,11 +211,13 @@ export function storage(options: {
const oldSetter = descriptor.set;
newDescriptor = {
...descriptor,
get(this: ReactiveStorageElement) {
return getValue();
},
set(this: ReactiveStorageElement, value) {
// Don't set the initial value if we have a value in localStorage
if (this.__initialized || getValue() === undefined) {
setValue(this, value);
this.requestUpdate(propertyKey, undefined);
}
oldSetter?.call(this, value);
},

View File

@@ -1,4 +1,4 @@
import { callService, type HassEntity } from "home-assistant-js-websocket";
import type { HassEntity } from "home-assistant-js-websocket";
import { computeStateDomain } from "./compute_state_domain";
import { isUnavailableState, UNAVAILABLE } from "../../data/entity";
import type { HomeAssistant } from "../../types";
@@ -62,7 +62,7 @@ export const toggleGroupEntities = (
const entitiesIds = states.map((stateObj) => stateObj.entity_id);
callService(hass.connection, domain, service, {
hass.callService(domain, service, {
entity_id: entitiesIds,
});
};

View File

@@ -1,14 +1,15 @@
import { mdiTextureBox } from "@mdi/js";
import { mdiDrag, mdiTextureBox } from "@mdi/js";
import type { TemplateResult } from "lit";
import { LitElement, css, html } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { computeFloorName } from "../common/entity/compute_floor_name";
import { getAreaContext } from "../common/entity/context/get_area_context";
import { stringCompare } from "../common/string/compare";
import { areaCompare } from "../data/area_registry";
import type { FloorRegistryEntry } from "../data/floor_registry";
import { getFloors } from "../panels/lovelace/strategies/areas/helpers/areas-strategy-helper";
import type { HomeAssistant } from "../types";
import "./ha-expansion-panel";
import "./ha-floor-icon";
@@ -17,9 +18,14 @@ import type { DisplayItem, DisplayValue } from "./ha-items-display-editor";
import "./ha-svg-icon";
import "./ha-textfield";
export interface AreasDisplayValue {
hidden?: string[];
order?: string[];
export interface AreasFloorsDisplayValue {
areas_display?: {
hidden?: string[];
order?: string[];
};
floors_display?: {
order?: string[];
};
}
const UNASSIGNED_FLOOR = "__unassigned__";
@@ -30,12 +36,10 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
@property() public label?: string;
@property({ attribute: false }) public value?: AreasDisplayValue;
@property({ attribute: false }) public value?: AreasFloorsDisplayValue;
@property() public helper?: string;
@property({ type: Boolean }) public expanded = false;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = false;
@@ -44,51 +48,78 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
public showNavigationButton = false;
protected render(): TemplateResult {
const groupedItems = this._groupedItems(this.hass.areas, this.hass.floors);
const groupedAreasItems = this._groupedAreasItems(
this.hass.areas,
this.hass.floors
);
const filteredFloors = this._sortedFloors(this.hass.floors).filter(
const filteredFloors = this._sortedFloors(
this.hass.floors,
this.value?.floors_display?.order
).filter(
(floor) =>
// Only include floors that have areas assigned to them
groupedItems[floor.floor_id]?.length > 0
groupedAreasItems[floor.floor_id]?.length > 0
);
const value: DisplayValue = {
order: this.value?.order ?? [],
hidden: this.value?.hidden ?? [],
order: this.value?.areas_display?.order ?? [],
hidden: this.value?.areas_display?.hidden ?? [],
};
const canReorderFloors =
filteredFloors.filter((floor) => floor.floor_id !== UNASSIGNED_FLOOR)
.length > 1;
return html`
<ha-expansion-panel
outlined
.header=${this.label}
.expanded=${this.expanded}
${this.label ? html`<label>${this.label}</label>` : nothing}
<ha-sortable
draggable-selector=".draggable"
handle-selector=".handle"
@item-moved=${this._floorMoved}
.disabled=${this.disabled || !canReorderFloors}
>
<ha-svg-icon slot="leading-icon" .path=${mdiTextureBox}></ha-svg-icon>
${filteredFloors.map(
(floor) => html`
<div class="floor">
<div class="header">
<ha-floor-icon .floor=${floor}></ha-floor-icon>
<p>${computeFloorName(floor)}</p>
</div>
<div class="areas">
<div>
${repeat(
filteredFloors,
(floor) => floor.floor_id,
(floor: FloorRegistryEntry) => html`
<ha-expansion-panel
outlined
.header=${computeFloorName(floor)}
left-chevron
class=${floor.floor_id === UNASSIGNED_FLOOR ? "" : "draggable"}
>
<ha-floor-icon
slot="leading-icon"
.floor=${floor}
></ha-floor-icon>
${floor.floor_id === UNASSIGNED_FLOOR || !canReorderFloors
? nothing
: html`
<ha-svg-icon
class="handle"
slot="icons"
.path=${mdiDrag}
></ha-svg-icon>
`}
<ha-items-display-editor
.hass=${this.hass}
.items=${groupedItems[floor.floor_id] || []}
.items=${groupedAreasItems[floor.floor_id]}
.value=${value}
.floorId=${floor.floor_id}
@value-changed=${this._areaDisplayChanged}
.showNavigationButton=${this.showNavigationButton}
></ha-items-display-editor>
</div>
</div>
`
)}
</ha-expansion-panel>
</ha-expansion-panel>
`
)}
</div>
</ha-sortable>
`;
}
private _groupedItems = memoizeOne(
private _groupedAreasItems = memoizeOne(
(
hassAreas: HomeAssistant["areas"],
// update items if floors change
@@ -112,7 +143,6 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
label: area.name,
icon: area.icon ?? undefined,
iconPath: mdiTextureBox,
description: floor?.name,
});
return acc;
@@ -124,20 +154,19 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
);
private _sortedFloors = memoizeOne(
(hassFloors: HomeAssistant["floors"]): FloorRegistryEntry[] => {
const floors = Object.values(hassFloors).sort((floorA, floorB) => {
if (floorA.level !== floorB.level) {
return (floorA.level ?? 0) - (floorB.level ?? 0);
}
return stringCompare(floorA.name, floorB.name);
});
(
hassFloors: HomeAssistant["floors"],
order: string[] | undefined
): FloorRegistryEntry[] => {
const floors = getFloors(hassFloors, order);
const noFloors = floors.length === 0;
floors.push({
floor_id: UNASSIGNED_FLOOR,
name: this.hass.localize(
"ui.panel.lovelace.strategy.areas.unassigned_areas"
),
name: noFloors
? this.hass.localize("ui.panel.lovelace.strategy.areas.areas")
: this.hass.localize("ui.panel.lovelace.strategy.areas.other_areas"),
icon: null,
level: 999999,
level: null,
aliases: [],
created_at: 0,
modified_at: 0,
@@ -146,68 +175,101 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
}
);
private async _areaDisplayChanged(ev) {
private _floorMoved(ev: CustomEvent<HASSDomEvents["item-moved"]>) {
ev.stopPropagation();
const value = ev.detail.value as DisplayValue;
const currentFloorId = ev.currentTarget.floorId;
const newIndex = ev.detail.newIndex;
const oldIndex = ev.detail.oldIndex;
const floorIds = this._sortedFloors(
this.hass.floors,
this.value?.floors_display?.order
).map((floor) => floor.floor_id);
const newOrder = [...floorIds];
const movedFloorId = newOrder.splice(oldIndex, 1)[0];
newOrder.splice(newIndex, 0, movedFloorId);
const newValue: AreasFloorsDisplayValue = {
areas_display: this.value?.areas_display,
floors_display: {
order: newOrder,
},
};
if (newValue.floors_display?.order?.length === 0) {
delete newValue.floors_display.order;
}
fireEvent(this, "value-changed", { value: newValue });
}
const floorIds = this._sortedFloors(this.hass.floors).map(
(floor) => floor.floor_id
);
private async _areaDisplayChanged(ev: CustomEvent<{ value: DisplayValue }>) {
ev.stopPropagation();
const value = ev.detail.value;
const currentFloorId = (ev.currentTarget as any).floorId;
const floorIds = this._sortedFloors(
this.hass.floors,
this.value?.floors_display?.order
).map((floor) => floor.floor_id);
const oldAreaDisplay = this.value?.areas_display ?? {};
const oldHidden = oldAreaDisplay?.hidden ?? [];
const oldOrder = oldAreaDisplay?.order ?? [];
const newHidden: string[] = [];
const newOrder: string[] = [];
for (const floorId of floorIds) {
if (currentFloorId === floorId) {
if ((currentFloorId ?? UNASSIGNED_FLOOR) === floorId) {
newHidden.push(...(value.hidden ?? []));
newOrder.push(...(value.order ?? []));
continue;
}
const hidden = this.value?.hidden?.filter(
(areaId) => this.hass.areas[areaId]?.floor_id === floorId
);
if (hidden) {
const hidden = oldHidden.filter((areaId) => {
const id = this.hass.areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR;
return id === floorId;
});
if (hidden?.length) {
newHidden.push(...hidden);
}
const order = this.value?.order?.filter(
(areaId) => this.hass.areas[areaId]?.floor_id === floorId
);
if (order) {
const order = oldOrder.filter((areaId) => {
const id = this.hass.areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR;
return id === floorId;
});
if (order?.length) {
newOrder.push(...order);
}
}
const newValue: AreasDisplayValue = {
hidden: newHidden,
order: newOrder,
const newValue: AreasFloorsDisplayValue = {
areas_display: {
hidden: newHidden,
order: newOrder,
},
floors_display: this.value?.floors_display,
};
if (newValue.hidden?.length === 0) {
delete newValue.hidden;
if (newValue.areas_display?.hidden?.length === 0) {
delete newValue.areas_display.hidden;
}
if (newValue.order?.length === 0) {
delete newValue.order;
if (newValue.areas_display?.order?.length === 0) {
delete newValue.areas_display.order;
}
if (newValue.floors_display?.order?.length === 0) {
delete newValue.floors_display.order;
}
fireEvent(this, "value-changed", { value: newValue });
}
static styles = css`
.floor .header p {
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
flex: 1:
ha-expansion-panel {
margin-bottom: 8px;
--expansion-panel-summary-padding: 0 16px;
}
.floor .header {
margin: 16px 0 8px 0;
padding: 0 8px;
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
ha-expansion-panel [slot="leading-icon"] {
margin-inline-end: 16px;
}
label {
display: block;
font-weight: var(--ha-font-weight-bold);
margin-bottom: 8px;
}
`;
}

View File

@@ -61,8 +61,8 @@ export class HaCodeEditor extends ReactiveElement {
@property({ type: Boolean }) public error = false;
@property({ type: Boolean, attribute: "enable-fullscreen" })
public enableFullscreen = true;
@property({ type: Boolean, attribute: "disable-fullscreen" })
public disableFullscreen = false;
@state() private _value = "";
@@ -179,7 +179,7 @@ export class HaCodeEditor extends ReactiveElement {
if (changedProps.has("_isFullscreen")) {
this.classList.toggle("fullscreen", this._isFullscreen);
}
if (changedProps.has("enableFullscreen")) {
if (changedProps.has("disableFullscreen")) {
this._updateFullscreenButton();
}
}
@@ -263,7 +263,7 @@ export class HaCodeEditor extends ReactiveElement {
private _updateFullscreenButton() {
const existingButton = this.renderRoot.querySelector(".fullscreen-button");
if (!this.enableFullscreen) {
if (this.disableFullscreen) {
// Remove button if it exists and fullscreen is disabled
if (existingButton) {
existingButton.remove();
@@ -317,7 +317,7 @@ export class HaCodeEditor extends ReactiveElement {
e.preventDefault();
e.stopPropagation();
this._toggleFullscreen();
} else if (e.key === "F11" && this.enableFullscreen) {
} else if (e.key === "F11" && !this.disableFullscreen) {
e.preventDefault();
e.stopPropagation();
this._toggleFullscreen();
@@ -557,11 +557,11 @@ export class HaCodeEditor extends ReactiveElement {
position: absolute;
top: 8px;
right: 8px;
z-index: 10;
z-index: 1;
color: var(--secondary-text-color);
background-color: var(--card-background-color);
background-color: var(--secondary-background-color);
border-radius: 50%;
opacity: 0.6;
opacity: 0.9;
transition: opacity 0.2s;
--mdc-icon-button-size: 32px;
--mdc-icon-size: 18px;
@@ -589,17 +589,17 @@ export class HaCodeEditor extends ReactiveElement {
right: 0 !important;
bottom: 0 !important;
z-index: 9999 !important;
background-color: var(--primary-background-color) !important;
background-color: var(
--code-editor-background-color,
var(--card-background-color)
) !important;
margin: 0 !important;
padding: 16px !important;
/* Respect iOS safe areas while accounting for header */
padding-top: max(16px, env(safe-area-inset-top)) !important;
padding-left: max(16px, env(safe-area-inset-left)) !important;
padding-right: max(16px, env(safe-area-inset-right)) !important;
padding-bottom: max(16px, env(safe-area-inset-bottom)) !important;
padding-top: var(--safe-area-inset-top) !important;
padding-left: var(--safe-area-inset-left) !important;
padding-right: var(--safe-area-inset-right) !important;
padding-bottom: var(--safe-area-inset-bottom) !important;
box-sizing: border-box !important;
display: flex !important;
flex-direction: column !important;
display: block !important;
}
:host(.fullscreen) .cm-editor {
@@ -609,12 +609,8 @@ export class HaCodeEditor extends ReactiveElement {
}
:host(.fullscreen) .fullscreen-button {
position: fixed;
top: calc(
var(--header-height, 56px) + max(8px, env(safe-area-inset-top))
);
right: max(24px, calc(env(safe-area-inset-right) + 8px));
z-index: 10000;
top: calc(var(--safe-area-inset-top, 0px) + 8px);
right: calc(var(--safe-area-inset-right, 0px) + 8px);
}
`;
}

View File

@@ -369,7 +369,6 @@ export class HaComboBox extends LitElement {
}
vaadin-combo-box-light {
position: relative;
--vaadin-combo-box-overlay-max-height: calc(45vh - 56px);
}
ha-combo-box-textfield {
width: 100%;

View File

@@ -26,7 +26,6 @@ export class HaControlButtonGroup extends LitElement {
.container {
display: flex;
flex-direction: row;
justify-content: var(--control-button-group-alignment, start);
width: 100%;
height: 100%;
}

View File

@@ -14,6 +14,7 @@ import "./ha-check-list-item";
import "./ha-expansion-panel";
import "./ha-icon-button";
import "./ha-list";
import { deepEqual } from "../common/util/deep-equal";
@customElement("ha-filter-blueprints")
export class HaFilterBlueprints extends LitElement {
@@ -34,10 +35,11 @@ export class HaFilterBlueprints extends LitElement {
public willUpdate(properties: PropertyValues) {
super.willUpdate(properties);
if (!this.hasUpdated) {
if (this.value?.length) {
this._findRelated();
}
if (
properties.has("value") &&
!deepEqual(this.value, properties.get("value"))
) {
this._findRelated();
}
}
@@ -130,17 +132,15 @@ export class HaFilterBlueprints extends LitElement {
}
this.value = value;
this._findRelated();
}
private async _findRelated() {
if (!this.value?.length) {
this.value = [];
fireEvent(this, "data-table-filter-changed", {
value: [],
items: undefined,
});
this.value = [];
return;
}

View File

@@ -6,6 +6,7 @@ import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { computeDeviceNameDisplay } from "../common/entity/compute_device_name";
import { stringCompare } from "../common/string/compare";
import { deepEqual } from "../common/util/deep-equal";
import type { RelatedResult } from "../data/search";
import { findRelated } from "../data/search";
import { haStyleScrollbar } from "../resources/styles";
@@ -37,9 +38,13 @@ export class HaFilterDevices extends LitElement {
if (!this.hasUpdated) {
loadVirtualizer();
if (this.value?.length) {
this._findRelated();
}
}
if (
properties.has("value") &&
!deepEqual(this.value, properties.get("value"))
) {
this._findRelated();
}
}
@@ -110,7 +115,6 @@ export class HaFilterDevices extends LitElement {
this.value = [...(this.value || []), value];
}
listItem.selected = this.value?.includes(value);
this._findRelated();
}
protected updated(changed) {
@@ -160,11 +164,11 @@ export class HaFilterDevices extends LitElement {
const relatedPromises: Promise<RelatedResult>[] = [];
if (!this.value?.length) {
this.value = [];
fireEvent(this, "data-table-filter-changed", {
value: [],
items: undefined,
});
this.value = [];
return;
}
@@ -176,7 +180,6 @@ export class HaFilterDevices extends LitElement {
relatedPromises.push(findRelated(this.hass, "device", deviceId));
}
}
this.value = value;
const results = await Promise.all(relatedPromises);
const items = new Set<string>();
for (const result of results) {

View File

@@ -17,6 +17,7 @@ import "./ha-expansion-panel";
import "./ha-list";
import "./ha-state-icon";
import "./search-input-outlined";
import { deepEqual } from "../common/util/deep-equal";
@customElement("ha-filter-entities")
export class HaFilterEntities extends LitElement {
@@ -39,9 +40,13 @@ export class HaFilterEntities extends LitElement {
if (!this.hasUpdated) {
loadVirtualizer();
if (this.value?.length) {
this._findRelated();
}
}
if (
properties.has("value") &&
!deepEqual(this.value, properties.get("value"))
) {
this._findRelated();
}
}
@@ -131,7 +136,6 @@ export class HaFilterEntities extends LitElement {
this.value = [...(this.value || []), value];
}
listItem.selected = this.value?.includes(value);
this._findRelated();
}
private _expandedWillChange(ev) {
@@ -178,11 +182,11 @@ export class HaFilterEntities extends LitElement {
const relatedPromises: Promise<RelatedResult>[] = [];
if (!this.value?.length) {
this.value = [];
fireEvent(this, "data-table-filter-changed", {
value: [],
items: undefined,
});
this.value = [];
return;
}

View File

@@ -20,6 +20,7 @@ import "./ha-icon-button";
import "./ha-list";
import "./ha-svg-icon";
import "./ha-tree-indicator";
import { deepEqual } from "../common/util/deep-equal";
@customElement("ha-filter-floor-areas")
export class HaFilterFloorAreas extends LitElement {
@@ -41,10 +42,11 @@ export class HaFilterFloorAreas extends LitElement {
public willUpdate(properties: PropertyValues) {
super.willUpdate(properties);
if (!this.hasUpdated) {
if (this.value?.floors?.length || this.value?.areas?.length) {
this._findRelated();
}
if (
properties.has("value") &&
!deepEqual(this.value, properties.get("value"))
) {
this._findRelated();
}
}
@@ -174,8 +176,6 @@ export class HaFilterFloorAreas extends LitElement {
}
listItem.selected = this.value[type]?.includes(value);
this._findRelated();
}
protected updated(changed) {
@@ -188,10 +188,6 @@ export class HaFilterFloorAreas extends LitElement {
}
}
protected firstUpdated() {
this._findRelated();
}
private _expandedWillChange(ev) {
this._shouldRender = ev.detail.expanded;
}
@@ -226,6 +222,7 @@ export class HaFilterFloorAreas extends LitElement {
!this.value ||
(!this.value.areas?.length && !this.value.floors?.length)
) {
this.value = {};
fireEvent(this, "data-table-filter-changed", {
value: {},
items: undefined,

View File

@@ -122,22 +122,6 @@ export class HaItemDisplayEditor extends LitElement {
${description
? html`<span slot="supporting-text">${description}</span>`
: nothing}
${isVisible && !disableSorting
? html`
<ha-svg-icon
tabindex=${ifDefined(
this.showNavigationButton ? "0" : undefined
)}
.idx=${idx}
@keydown=${this.showNavigationButton
? this._dragHandleKeydown
: undefined}
class="handle"
.path=${mdiDrag}
slot="start"
></ha-svg-icon>
`
: html`<ha-svg-icon slot="start"></ha-svg-icon>`}
${!showIcon
? nothing
: icon
@@ -162,6 +146,9 @@ export class HaItemDisplayEditor extends LitElement {
<span slot="end"> ${this.actionsRenderer(item)} </span>
`
: nothing}
${this.showNavigationButton
? html`<ha-icon-next slot="end"></ha-icon-next>`
: nothing}
<ha-icon-button
.path=${isVisible ? mdiEye : mdiEyeOff}
slot="end"
@@ -174,9 +161,22 @@ export class HaItemDisplayEditor extends LitElement {
.value=${value}
@click=${this._toggle}
></ha-icon-button>
${this.showNavigationButton
? html` <ha-icon-next slot="end"></ha-icon-next> `
: nothing}
${isVisible && !disableSorting
? html`
<ha-svg-icon
tabindex=${ifDefined(
this.showNavigationButton ? "0" : undefined
)}
.idx=${idx}
@keydown=${this.showNavigationButton
? this._dragHandleKeydown
: undefined}
class="handle"
.path=${mdiDrag}
slot="end"
></ha-svg-icon>
`
: html`<ha-svg-icon slot="end"></ha-svg-icon>`}
</ha-md-list-item>
`;
}

View File

@@ -122,11 +122,7 @@ export class HaObjectSelector extends LitElement {
}
protected render() {
if (!this.selector.object) {
return nothing;
}
if (this.selector.object.fields) {
if (this.selector.object?.fields) {
if (this.selector.object.multiple) {
const items = ensureArray(this.value ?? []);
return html`

View File

@@ -89,6 +89,7 @@ export class HaSettingsRow extends LitElement {
display: var(--settings-row-content-display, flex);
justify-content: flex-end;
flex: 1;
min-width: 0;
padding: 16px 0;
}
.content ::slotted(*) {

View File

@@ -44,6 +44,9 @@ export class HaYamlEditor extends LitElement {
@property({ attribute: "read-only", type: Boolean }) public readOnly = false;
@property({ type: Boolean, attribute: "disable-fullscreen" })
public disableFullscreen = false;
@property({ type: Boolean }) public required = false;
@property({ attribute: "copy-clipboard", type: Boolean })
@@ -110,6 +113,7 @@ export class HaYamlEditor extends LitElement {
.hass=${this.hass}
.value=${this._yaml}
.readOnly=${this.readOnly}
.disableFullscreen=${this.disableFullscreen}
mode="yaml"
autocomplete-entities
autocomplete-icons

View File

@@ -1,5 +1,4 @@
import { mdiContentSave, mdiMedal, mdiTrophy } from "@mdi/js";
import { mdiHomeAssistant } from "../resources/home-assistant-logo-svg";
import type { LocalizeKeys } from "../common/translations/localize";
/**
@@ -26,11 +25,6 @@ export const QUALITY_SCALE_MAP: Record<
translationKey:
"ui.panel.config.integrations.config_entry.platinum_quality",
},
internal: {
icon: mdiHomeAssistant,
translationKey:
"ui.panel.config.integrations.config_entry.internal_integration",
},
legacy: {
icon: mdiContentSave,
translationKey:

View File

@@ -114,9 +114,13 @@ const getLogbookDataFromServer = (
export const subscribeLogbook = (
hass: HomeAssistant,
callbackFunction: (message: LogbookStreamMessage) => void,
callbackFunction: (
message: LogbookStreamMessage,
subscriptionId: number
) => void,
startDate: string,
endDate: string,
subscriptionId: number,
entityIds?: string[],
deviceIds?: string[]
): Promise<UnsubscribeFunc> => {
@@ -140,7 +144,7 @@ export const subscribeLogbook = (
params.device_ids = deviceIds;
}
return hass.connection.subscribeMessage<LogbookStreamMessage>(
(message) => callbackFunction(message),
(message) => callbackFunction(message, subscriptionId),
params
);
};

View File

@@ -286,7 +286,7 @@ class DataEntryFlowDialog extends LitElement {
scrimClickAction
escapeKeyAction
hideActions
.heading=${dialogTitle}
.heading=${dialogTitle || true}
>
<ha-dialog-header slot="heading">
<ha-icon-button

View File

@@ -35,10 +35,16 @@ export const showConfigFlowDialog = (
return step;
},
fetchFlow: async (hass, flowId) => {
const step = await fetchConfigFlow(hass, flowId);
await hass.loadFragmentTranslation("config");
await hass.loadBackendTranslation("config", step.handler);
await hass.loadBackendTranslation("selector", step.handler);
const [step] = await Promise.all([
fetchConfigFlow(hass, flowId),
hass.loadFragmentTranslation("config"),
]);
await Promise.all([
hass.loadBackendTranslation("config", step.handler),
hass.loadBackendTranslation("selector", step.handler),
// Used as fallback if no header defined for step
hass.loadBackendTranslation("title", step.handler),
]);
return step;
},
handleFlowStep: handleConfigFlowStep,

View File

@@ -502,6 +502,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
.readOnly=${this._readOnly}
@value-changed=${this._yamlChanged}
.showErrors=${false}
disable-fullscreen
></ha-yaml-editor>`
: nothing}
</div>

View File

@@ -173,6 +173,7 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
.content=${value?.description}
></ha-markdown>
${html`<ha-selector
narrow
.hass=${this.hass}
.selector=${selector}
.key=${key}

View File

@@ -1317,9 +1317,13 @@ export class HaConfigDevicePage extends LitElement {
// eslint-disable-next-line no-await-in-loop
(await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.devices.confirm_disable_config_entry",
{ entry_name: config_entry.title }
"ui.panel.config.devices.confirm_disable_config_entry_title"
),
text: this.hass.localize(
"ui.panel.config.devices.confirm_disable_config_entry_message",
{ name: config_entry.title }
),
destructive: true,
confirmText: this.hass.localize("ui.common.yes"),
dismissText: this.hass.localize("ui.common.no"),
}))

View File

@@ -1099,10 +1099,10 @@ ${
}
protected firstUpdated() {
this._setFiltersFromUrl();
fetchEntitySourcesWithCache(this.hass).then((sources) => {
this._entitySources = sources;
});
this._setFiltersFromUrl();
if (Object.keys(this._filters).length) {
return;
}
@@ -1116,7 +1116,7 @@ ${
const configEntry = this._searchParms.get("config_entry");
const subEntry = this._searchParms.get("sub_entry");
const device = this._searchParms.get("device");
const label = this._searchParms.has("label");
const label = this._searchParms.get("label");
if (!domain && !configEntry && !label && !device) {
return;
@@ -1128,21 +1128,10 @@ ${
"ha-filter-states": [],
"ha-filter-integrations": domain ? [domain] : [],
"ha-filter-devices": device ? [device] : [],
"ha-filter-labels": label ? [label] : [],
config_entry: configEntry ? [configEntry] : [],
sub_entry: subEntry ? [subEntry] : [],
};
this._filterLabel();
}
private _filterLabel() {
const label = this._searchParms.get("label");
if (!label) {
return;
}
this._filters = {
...this._filters,
"ha-filter-labels": [label],
};
}
private _clearFilter() {
@@ -1152,6 +1141,11 @@ ${
public willUpdate(changedProps: PropertyValues): void {
super.willUpdate(changedProps);
if (!this.hasUpdated) {
this._setFiltersFromUrl();
}
const oldHass = changedProps.get("hass");
let changed = false;
if (!this.hass || !this._entities) {

View File

@@ -1,10 +1,11 @@
import {
mdiCogOutline,
mdiDelete,
mdiDevices,
mdiDotsVertical,
mdiPencil,
mdiShapeOutline,
mdiStopCircleOutline,
mdiTransitConnectionVariant,
} from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
@@ -57,111 +58,118 @@ class HaConfigEntryDeviceRow extends LitElement {
area ? area.name : undefined,
].filter(Boolean);
return html`<ha-md-list-item @click=${this.narrow ? this._handleNavigateToDevice : undefined} class=${classMap({ disabled: Boolean(device.disabled_by) })}>
<ha-svg-icon .path=${mdiDevices} slot="start"></ha-svg-icon>
<div slot="headline"></div>${computeDeviceNameDisplay(device, this.hass)}</div>
return html`<ha-md-list-item
type="button"
@click=${this._handleNavigateToDevice}
class=${classMap({ disabled: Boolean(device.disabled_by) })}
>
<ha-svg-icon
.path=${device.entry_type === "service"
? mdiTransitConnectionVariant
: mdiDevices}
slot="start"
></ha-svg-icon>
<div slot="headline">${computeDeviceNameDisplay(device, this.hass)}</div>
<span slot="supporting-text"
>${supportingText.join(" • ")}
${supportingText.length && entities.length ? " • " : nothing}
${
entities.length
? this.narrow
? this.hass.localize(
"ui.panel.config.integrations.config_entry.entities",
{ count: entities.length }
)
: html`<a
href=${`/config/entities/?historyBack=1&device=${device.id}`}
>${this.hass.localize(
"ui.panel.config.integrations.config_entry.entities",
{ count: entities.length }
)}</a
>`
: nothing
}</span
${entities.length
? this.hass.localize(
"ui.panel.config.integrations.config_entry.entities",
{ count: entities.length }
)
: nothing}</span
>
${
!this.narrow
? html`<ha-icon-button-next
slot="end"
@click=${this._handleNavigateToDevice}
>
</ha-icon-button-next>`
: nothing
}
</ha-icon-button>
${!this.narrow
? html`<ha-icon-next slot="end"> </ha-icon-next>`
: nothing}
<div class="vertical-divider" slot="end" @click=${stopPropagation}></div>
${
!this.narrow
? html`<ha-icon-button
slot="end"
@click=${this._handleConfigureDevice}
.path=${mdiPencil}
.label=${this.hass.localize(
"ui.panel.config.integrations.config_entry.device.configure"
)}
></ha-icon-button>`
: nothing
}
</ha-icon-button>
<ha-md-button-menu positioning="popover" slot="end" @click=${stopPropagation}>
${!this.narrow
? html`<ha-icon-button
slot="end"
@click=${this._handleEditDevice}
.path=${mdiPencil}
.label=${this.hass.localize(
"ui.panel.config.integrations.config_entry.device.edit"
)}
></ha-icon-button>`
: nothing}
<ha-md-button-menu
positioning="popover"
slot="end"
@click=${stopPropagation}
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
${
this.narrow
? html`<ha-md-menu-item @click=${this._handleConfigureDevice}>
<ha-svg-icon .path=${mdiCogOutline} slot="start"></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.device.configure"
)}
</ha-md-menu-item>`
: nothing
}
<ha-md-menu-item class=${device.disabled_by !== "user" ? "warning" : ""} @click=${this._handleDisableDevice} .disabled=${device.disabled_by !== "user" && device.disabled_by}>
<ha-svg-icon .path=${mdiStopCircleOutline} slot="start"></ha-svg-icon>
${
device.disabled_by && device.disabled_by !== "user"
? this.hass.localize(
"ui.dialogs.device-registry-detail.enabled_cause",
{
type: this.hass.localize(
`ui.dialogs.device-registry-detail.type.${
device.entry_type || "device"
}`
),
cause: this.hass.localize(
`config_entry.disabled_by.${device.disabled_by}`
),
}
)
: device.disabled_by
? this.hass.localize(
"ui.panel.config.integrations.config_entry.device.enable"
)
: this.hass.localize(
"ui.panel.config.integrations.config_entry.device.disable"
)
}
</ha-md-menu-item>
${
this.entry.supports_remove_device
? html` <ha-md-menu-item
class="warning"
@click=${this._handleDeleteDevice}
${this.narrow
? html`<ha-md-menu-item @click=${this._handleEditDevice}>
<ha-svg-icon .path=${mdiPencil} slot="start"></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.device.edit"
)}
</ha-md-menu-item>`
: nothing}
${entities.length
? html`
<ha-md-menu-item
href=${`/config/entities/?historyBack=1&device=${device.id}`}
>
<ha-svg-icon .path=${mdiDelete} slot="start"></ha-svg-icon>
<ha-svg-icon
.path=${mdiShapeOutline}
slot="start"
></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.device.delete"
`ui.panel.config.integrations.config_entry.entities`,
{ count: entities.length }
)}
</ha-md-menu-item>`
: nothing
}
<ha-icon-next slot="end"></ha-icon-next>
</ha-md-menu-item>
`
: nothing}
<ha-md-menu-item
class=${device.disabled_by !== "user" ? "warning" : ""}
@click=${this._handleDisableDevice}
.disabled=${device.disabled_by !== "user" && device.disabled_by}
>
<ha-svg-icon .path=${mdiStopCircleOutline} slot="start"></ha-svg-icon>
${device.disabled_by && device.disabled_by !== "user"
? this.hass.localize(
"ui.dialogs.device-registry-detail.enabled_cause",
{
type: this.hass.localize(
`ui.dialogs.device-registry-detail.type.${
device.entry_type || "device"
}`
),
cause: this.hass.localize(
`config_entry.disabled_by.${device.disabled_by}`
),
}
)
: device.disabled_by
? this.hass.localize(
"ui.panel.config.integrations.config_entry.device.enable"
)
: this.hass.localize(
"ui.panel.config.integrations.config_entry.device.disable"
)}
</ha-md-menu-item>
${this.entry.supports_remove_device
? html`<ha-md-menu-item
class="warning"
@click=${this._handleDeleteDevice}
>
<ha-svg-icon .path=${mdiDelete} slot="start"></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.device.delete"
)}
</ha-md-menu-item>`
: nothing}
</ha-md-button-menu>
</ha-md-list-item> `;
}
@@ -169,7 +177,7 @@ class HaConfigEntryDeviceRow extends LitElement {
private _getEntities = (): EntityRegistryEntry[] =>
this.entities?.filter((entity) => entity.device_id === this.device.id);
private _handleConfigureDevice(ev: MouseEvent) {
private _handleEditDevice(ev: MouseEvent) {
ev.stopPropagation(); // Prevent triggering the click handler on the list item
showDeviceRegistryDetailDialog(this, {
device: this.device,
@@ -196,9 +204,13 @@ class HaConfigEntryDeviceRow extends LitElement {
!config_entry.disabled_by &&
(await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.devices.confirm_disable_config_entry",
{ entry_name: config_entry.title }
"ui.panel.config.devices.confirm_disable_config_entry_title"
),
text: this.hass.localize(
"ui.panel.config.devices.confirm_disable_config_entry_message",
{ name: config_entry.title }
),
destructive: true,
confirmText: this.hass.localize("ui.common.yes"),
dismissText: this.hass.localize("ui.common.no"),
}))
@@ -230,9 +242,13 @@ class HaConfigEntryDeviceRow extends LitElement {
if (disable) {
const confirm = await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_entry.device.confirm_disable",
"ui.panel.config.integrations.config_entry.device.confirm_disable_title"
),
text: this.hass.localize(
"ui.panel.config.integrations.config_entry.device.confirm_disable_message",
{ name: computeDeviceNameDisplay(this.device, this.hass) }
),
destructive: true,
confirmText: this.hass.localize("ui.common.yes"),
dismissText: this.hass.localize("ui.common.no"),
});
@@ -286,6 +302,8 @@ class HaConfigEntryDeviceRow extends LitElement {
}
ha-md-list-item {
--md-list-item-leading-space: 56px;
--md-ripple-hover-color: transparent;
--md-ripple-pressed-color: transparent;
}
.disabled {
opacity: 0.5;

View File

@@ -1,7 +1,6 @@
import {
mdiAlertCircle,
mdiChevronDown,
mdiChevronUp,
mdiCogOutline,
mdiDelete,
mdiDevices,
@@ -58,6 +57,7 @@ import { showConfigEntrySystemOptionsDialog } from "../../../dialogs/config-entr
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
import { showSubConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-sub-config-flow";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { fileDownload } from "../../../util/file_download";
@@ -69,7 +69,6 @@ import {
import "./ha-config-entry-device-row";
import { renderConfigEntryError } from "./ha-config-integration-page";
import "./ha-config-sub-entry-row";
import { haStyle } from "../../../resources/styles";
@customElement("ha-config-entry-row")
class HaConfigEntryRow extends LitElement {
@@ -155,7 +154,10 @@ class HaConfigEntryRow extends LitElement {
statusLine.push(
html`<a
href=${`/config/entities/?historyBack=1&config_entry=${item.entry_id}`}
>${entities.length} entities</a
>${this.hass.localize(
"ui.panel.config.integrations.config_entry.entities",
{ count: entities.length }
)}</a
>`
);
}
@@ -178,8 +180,8 @@ class HaConfigEntryRow extends LitElement {
>
${subEntries.length || ownDevices.length
? html`<ha-icon-button
class="expand-button"
.path=${this._expanded ? mdiChevronDown : mdiChevronUp}
class="expand-button ${classMap({ expanded: this._expanded })}"
.path=${mdiChevronDown}
slot="start"
@click=${this._toggleExpand}
></ha-icon-button>`
@@ -405,47 +407,55 @@ class HaConfigEntryRow extends LitElement {
</ha-md-list-item>
${this._expanded
? subEntries.length
? html`<ha-md-list class="devices">
<ha-md-list-item @click=${this._toggleOwnDevices} type="button">
<ha-icon-button
class="expand-button"
.path=${this._devicesExpanded
? mdiChevronDown
: mdiChevronUp}
slot="start"
? html`${ownDevices.length
? html`<ha-md-list class="devices">
<ha-md-list-item
@click=${this._toggleOwnDevices}
type="button"
class="toggle-devices-row ${classMap({
expanded: this._devicesExpanded,
})}"
>
</ha-icon-button>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.devices_without_subentry"
)}
</ha-md-list-item>
${this._devicesExpanded
? ownDevices.map(
(device) =>
html`<ha-config-entry-device-row
.hass=${this.hass}
.narrow=${this.narrow}
.entry=${item}
.device=${device}
.entities=${entities}
></ha-config-entry-device-row>`
)
: nothing}
</ha-md-list>
${subEntries.map(
(subEntry) => html`
<ha-config-sub-entry-row
.hass=${this.hass}
.narrow=${this.narrow}
.manifest=${this.manifest}
.diagnosticHandler=${this.diagnosticHandler}
.entities=${this.entities}
.entry=${item}
.subEntry=${subEntry}
data-entry-id=${item.entry_id}
></ha-config-sub-entry-row>
`
)}`
<ha-icon-button
class="expand-button ${classMap({
expanded: this._devicesExpanded,
})}"
.path=${mdiChevronDown}
slot="start"
>
</ha-icon-button>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.devices_without_subentry"
)}
</ha-md-list-item>
${this._devicesExpanded
? ownDevices.map(
(device) =>
html`<ha-config-entry-device-row
.hass=${this.hass}
.narrow=${this.narrow}
.entry=${item}
.device=${device}
.entities=${entities}
></ha-config-entry-device-row>`
)
: nothing}
</ha-md-list>`
: nothing}
${subEntries.map(
(subEntry) => html`
<ha-config-sub-entry-row
.hass=${this.hass}
.narrow=${this.narrow}
.manifest=${this.manifest}
.diagnosticHandler=${this.diagnosticHandler}
.entities=${this.entities}
.entry=${item}
.subEntry=${subEntry}
data-entry-id=${item.entry_id}
></ha-config-sub-entry-row>
`
)}`
: html`
${ownDevices.map(
(device) =>
@@ -734,12 +744,20 @@ class HaConfigEntryRow extends LitElement {
css`
.expand-button {
margin: 0 -12px;
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
.expand-button.expanded {
transform: rotate(180deg);
}
ha-md-list {
border: 1px solid var(--divider-color);
border-radius: var(--ha-card-border-radius, 12px);
padding: 0;
}
:host([narrow]) {
margin-left: -12px;
margin-right: -12px;
}
ha-md-list.devices {
margin: 16px;
margin-top: 0;
@@ -750,6 +768,14 @@ class HaConfigEntryRow extends LitElement {
var(--md-sys-color-on-surface-variant, #49454f)
);
}
.toggle-devices-row {
overflow: hidden;
border-radius: var(--ha-card-border-radius, 12px);
}
.toggle-devices-row.expanded {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
`,
];
}

View File

@@ -380,6 +380,14 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
<div class="title">
<h1>${domainToName(this.hass.localize, this.domain)}</h1>
<div class="sub">
${this._manifest?.version != null
? html`<span class="version"
>${this.hass.localize(
"ui.panel.config.integrations.config_entry.version",
{ version: this._manifest.version }
)}</span
>`
: nothing}
${this._manifest?.is_built_in === false
? html`<div
class=${`integration-info ${
@@ -424,7 +432,8 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
)}
</div>`
: nothing}
${this._manifest?.quality_scale &&
${this._manifest?.is_built_in &&
this._manifest.quality_scale &&
Object.keys(QUALITY_SCALE_MAP).includes(
this._manifest.quality_scale
)
@@ -541,8 +550,9 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
<ha-button
slot="action"
@click=${this._handleDisableDebugLogging}
>${this.hass.localize("ui.common.disable")}</ha-button
>
${this.hass.localize("ui.common.disable")}
</ha-button>
</ha-alert>
</div>`
: nothing}
@@ -892,7 +902,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
}
.title {
display: flex;
gap: 8px;
gap: 4px;
flex-direction: column;
justify-content: space-between;
}
@@ -910,6 +920,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
display: flex;
flex-wrap: wrap;
gap: 8px 16px;
align-items: center;
}
.card-content {
padding: 16px 0 8px;
@@ -933,9 +944,6 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
width: 80px;
}
.version {
padding-top: 8px;
display: flex;
justify-content: center;
color: var(--secondary-text-color);
}
.overview .card-actions {
@@ -953,6 +961,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
}
.actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.section {
@@ -1007,9 +1016,6 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
ha-svg-icon.platinum-quality {
color: #727272;
}
ha-svg-icon.internal-quality {
color: var(--primary-color);
}
ha-svg-icon.legacy-quality {
color: var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38));
animation: unset;

View File

@@ -1,6 +1,5 @@
import {
mdiChevronDown,
mdiChevronUp,
mdiCogOutline,
mdiDelete,
mdiDevices,
@@ -10,6 +9,7 @@ import {
} from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import type { ConfigEntry, SubEntry } from "../../../data/config_entries";
import { deleteSubEntry } from "../../../data/config_entries";
import type { DeviceRegistryEntry } from "../../../data/device_registry";
@@ -56,8 +56,8 @@ class HaConfigSubEntryRow extends LitElement {
>
${devices.length || services.length
? html`<ha-icon-button
class="expand-button"
.path=${this._expanded ? mdiChevronDown : mdiChevronUp}
class="expand-button ${classMap({ expanded: this._expanded })}"
.path=${mdiChevronDown}
slot="start"
@click=${this._toggleExpand}
></ha-icon-button>`
@@ -239,6 +239,10 @@ class HaConfigSubEntryRow extends LitElement {
static styles = css`
.expand-button {
margin: 0 -12px;
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
.expand-button.expanded {
transform: rotate(180deg);
}
ha-md-list {
border: 1px solid var(--divider-color);

View File

@@ -321,6 +321,7 @@ export class HaSceneEditor extends PreventUnsavedMixin(
.defaultValue=${this._config}
@value-changed=${this._yamlChanged}
.showErrors=${false}
disable-fullscreen
></ha-yaml-editor>`;
}

View File

@@ -440,6 +440,7 @@ export class HaScriptEditor extends SubscribeMixin(
.hass=${this.hass}
.defaultValue=${this._preprocessYaml()}
.readOnly=${this._readOnly}
disable-fullscreen
@value-changed=${this._yamlChanged}
.showErrors=${false}
></ha-yaml-editor>`

View File

@@ -88,6 +88,8 @@ export class HaLogbook extends LitElement {
1000
);
private _logbookSubscriptionId = 0;
protected render() {
if (!isComponentLoaded(this.hass, "logbook")) {
return nothing;
@@ -278,13 +280,20 @@ export class HaLogbook extends LitElement {
}
try {
this._logbookSubscriptionId++;
this._unsubLogbook = subscribeLogbook(
this.hass,
(streamMessage) => {
(streamMessage, subscriptionId) => {
if (subscriptionId !== this._logbookSubscriptionId) {
// Ignore messages from previous subscriptions
return;
}
this._processOrQueueStreamMessage(streamMessage);
},
logbookPeriod.startTime.toISOString(),
logbookPeriod.endTime.toISOString(),
this._logbookSubscriptionId,
this.entityIds,
this.deviceIds
);

View File

@@ -25,9 +25,6 @@ export const cardFeatureStyles = css`
flex-basis: 20px;
--control-button-padding: 0px;
}
ha-control-button-group[no-stretch] > ha-control-button {
max-width: 48px;
}
ha-control-button {
--control-button-focus-color: var(--feature-color);
}

View File

@@ -1,5 +1,6 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { css, html, LitElement, nothing } from "lit";
import { classMap } from "lit/directives/class-map";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one";
@@ -229,7 +230,11 @@ class HuiAreaControlsCardFeature
}
return html`
<ha-control-button-group ?no-stretch=${this.position === "inline"}>
<ha-control-button-group
class=${classMap({
"no-stretch": this.position === "inline",
})}
>
${displayControls.map((control) => {
const button = AREA_CONTROLS_BUTTONS[control];
@@ -292,8 +297,22 @@ class HuiAreaControlsCardFeature
return [
cardFeatureStyles,
css`
:host {
pointer-events: none !important;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
ha-control-button-group {
--control-button-group-alignment: flex-end;
pointer-events: auto;
width: 100%;
}
ha-control-button-group.no-stretch {
width: auto;
max-width: 100%;
}
ha-control-button-group.no-stretch > ha-control-button {
width: 48px;
}
ha-control-button {
--active-color: var(--state-active-color);

View File

@@ -1,4 +1,4 @@
import { LitElement, html, nothing } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import type { HomeAssistant } from "../../../types";
import type { HuiErrorCard } from "../cards/hui-error-card";
@@ -56,6 +56,12 @@ export class HuiCardFeature extends LitElement {
}
return html`${element}`;
}
static styles = css`
:host > * {
pointer-events: auto;
}
`;
}
declare global {

View File

@@ -46,6 +46,7 @@ export class HuiCardFeatures extends LitElement {
--feature-height: 42px;
--feature-border-radius: 12px;
--feature-button-spacing: 12px;
pointer-events: none;
position: relative;
width: 100%;
display: flex;

View File

@@ -348,6 +348,14 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
return undefined;
}
// If only one entity, return its formatted state
if (entities.length === 1) {
const stateObj = entities[0];
return isUnavailableState(stateObj.state)
? ""
: this.hass.formatEntityState(stateObj);
}
// Use the first entity's unit_of_measurement for formatting
const uom = entities.find(
(entity) => entity.attributes.unit_of_measurement

View File

@@ -74,8 +74,6 @@ export class HuiDialogEditCard
@state() private _dirty = false;
@state() private _isEscapeEnabled = true;
public async showDialog(params: EditCardDialogParams): Promise<void> {
this._params = params;
this._GUImode = true;
@@ -93,9 +91,6 @@ export class HuiDialogEditCard
}
public closeDialog(): boolean {
this._isEscapeEnabled = true;
window.removeEventListener("dialog-closed", this._enableEscapeKeyClose);
window.removeEventListener("hass-more-info", this._disableEscapeKeyClose);
if (this._dirty) {
this._confirmCancel();
return false;
@@ -124,16 +119,6 @@ export class HuiDialogEditCard
}
}
private _enableEscapeKeyClose = (ev: any) => {
if (ev.detail.dialog === "ha-more-info-dialog") {
this._isEscapeEnabled = true;
}
};
private _disableEscapeKeyClose = () => {
this._isEscapeEnabled = false;
};
protected render() {
if (!this._params || !this._cardConfig) {
return nothing;
@@ -170,7 +155,7 @@ export class HuiDialogEditCard
<ha-dialog
open
scrimClickAction
.escapeKeyAction=${this._isEscapeEnabled ? undefined : ""}
escapeKeyAction
@keydown=${this._ignoreKeydown}
@closed=${this._cancel}
@opened=${this._opened}
@@ -304,8 +289,6 @@ export class HuiDialogEditCard
}
private _opened() {
window.addEventListener("dialog-closed", this._enableEscapeKeyClose);
window.addEventListener("hass-more-info", this._disableEscapeKeyClose);
this._cardEditorEl?.focusYamlEditor();
}

View File

@@ -144,6 +144,9 @@ class DialogDashboardStrategyEditor extends LitElement {
.path=${mdiClose}
></ha-icon-button>
<span slot="title" .title=${title}>${title}</span>
${this._params.title
? html`<span slot="subtitle">${this._params.title}</span>`
: nothing}
<ha-button-menu
corner="BOTTOM_END"
menu-corner="END"

View File

@@ -3,6 +3,7 @@ import type { LovelaceDashboardStrategyConfig } from "../../../../../data/lovela
export interface DashboardStrategyEditorDialogParams {
config: LovelaceDashboardStrategyConfig;
title?: string;
saveConfig: (config: LovelaceDashboardStrategyConfig) => void;
takeControl: () => void;
deleteDashboard: () => Promise<boolean>;

View File

@@ -89,6 +89,7 @@ class LovelaceFullConfigEditor extends LitElement {
.hass=${this.hass}
@value-changed=${this._yamlChanged}
@editor-save=${this._handleSave}
disable-fullscreen
dir="ltr"
>
</ha-code-editor>

View File

@@ -782,6 +782,7 @@ class HUIRoot extends LitElement {
showDashboardStrategyEditorDialog(this, {
config: this.lovelace!.rawConfig,
title: this.panel ? getPanelTitle(this.hass, this.panel) : undefined,
saveConfig: this.lovelace!.saveConfig,
takeControl: () => {
showSaveDialog(this, {

View File

@@ -22,6 +22,9 @@ export interface AreasDashboardStrategyConfig {
hidden?: string[];
order?: string[];
};
floors_display?: {
order?: string[];
};
areas_options?: Record<string, AreaOptions>;
}
@@ -78,13 +81,13 @@ export class AreasDashboardStrategy extends ReactiveElement {
return {
views: [
{
title: "Home",
icon: "mdi:home",
path: "home",
strategy: {
type: "areas-overview",
areas_display: config.areas_display,
areas_options: config.areas_options,
floors_display: config.floors_display,
} satisfies AreasViewStrategyConfig,
},
...areaViews,

View File

@@ -1,6 +1,5 @@
import { ReactiveElement } from "lit";
import { customElement } from "lit/decorators";
import { stringCompare } from "../../../../common/string/compare";
import { floorDefaultIcon } from "../../../../components/ha-floor-icon";
import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
@@ -9,7 +8,11 @@ import { getAreaControlEntities } from "../../card-features/hui-area-controls-ca
import { AREA_CONTROLS, type AreaControl } from "../../card-features/types";
import type { AreaCardConfig, HeadingCardConfig } from "../../cards/types";
import type { EntitiesDisplay } from "./area-view-strategy";
import { computeAreaPath, getAreas } from "./helpers/areas-strategy-helper";
import {
computeAreaPath,
getAreas,
getFloors,
} from "./helpers/areas-strategy-helper";
const UNASSIGNED_FLOOR = "__unassigned__";
@@ -23,6 +26,9 @@ export interface AreasViewStrategyConfig {
hidden?: string[];
order?: string[];
};
floors_display?: {
order?: string[];
};
areas_options?: Record<string, AreaOptions>;
}
@@ -32,43 +38,35 @@ export class AreasOverviewViewStrategy extends ReactiveElement {
config: AreasViewStrategyConfig,
hass: HomeAssistant
): Promise<LovelaceViewConfig> {
const areas = getAreas(
const displayedAreas = getAreas(
hass.areas,
config.areas_display?.hidden,
config.areas_display?.order
);
const floors = Object.values(hass.floors);
floors.sort((floorA, floorB) => {
if (floorA.level !== floorB.level) {
return (floorA.level ?? 0) - (floorB.level ?? 0);
}
return stringCompare(floorA.name, floorB.name);
});
const floors = getFloors(hass.floors, config.floors_display?.order);
const floorSections = [
...floors,
{
floor_id: UNASSIGNED_FLOOR,
name: hass.localize(
"ui.panel.lovelace.strategy.areas.unassigned_areas"
),
name: hass.localize("ui.panel.lovelace.strategy.areas.other_areas"),
level: null,
icon: null,
},
]
.map<LovelaceSectionConfig | undefined>((floor) => {
const areasInFloors = areas.filter(
.map((floor) => {
const areasInFloors = displayedAreas.filter(
(area) =>
area.floor_id === floor.floor_id ||
(!area.floor_id && floor.floor_id === UNASSIGNED_FLOOR)
);
if (areasInFloors.length === 0) {
return undefined;
}
const areasCards = areasInFloors.map<AreaCardConfig>((area) => {
return [floor, areasInFloors] as const;
})
.filter(([_, areas]) => areas.length)
.map<LovelaceSectionConfig | undefined>(([floor, areas], _, array) => {
const areasCards = areas.map<AreaCardConfig>((area) => {
const path = computeAreaPath(area.area_id);
const areaOptions = config.areas_options?.[area.area_id] || {};
@@ -91,20 +89,19 @@ export class AreasOverviewViewStrategy extends ReactiveElement {
(control) => controlEntities[control].length > 0
);
const sensorClasses: string[] = [];
if (area.temperature_entity_id) {
sensorClasses.push("temperature");
}
if (area.humidity_entity_id) {
sensorClasses.push("humidity");
}
return {
type: "area",
area: area.area_id,
display_type: "compact",
sensor_classes: ["temperature", "humidity"],
alert_classes: [
"water_leak",
"smoke",
"gas",
"co",
"motion",
"occupancy",
"presence",
],
sensor_classes: sensorClasses,
exclude_entities: hiddenEntities,
features: filteredControls.length
? [
@@ -123,10 +120,17 @@ export class AreasOverviewViewStrategy extends ReactiveElement {
};
});
const noFloors =
array.length === 1 && floor.floor_id === UNASSIGNED_FLOOR;
const headingTitle = noFloors
? hass.localize("ui.panel.lovelace.strategy.areas.areas")
: floor.name;
const headingCard: HeadingCardConfig = {
type: "heading",
heading_style: "title",
heading: floor.name,
heading: headingTitle,
icon: floor.icon || floorDefaultIcon(floor),
};

View File

@@ -1,28 +1,32 @@
import { mdiThermometerWater } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../../../../../components/ha-areas-display-editor";
import type { AreasDisplayValue } from "../../../../../components/ha-areas-display-editor";
import "../../../../../components/ha-areas-floors-display-editor";
import type { AreasFloorsDisplayValue } from "../../../../../components/ha-areas-floors-display-editor";
import "../../../../../components/ha-entities-display-editor";
import "../../../../../components/ha-icon";
import "../../../../../components/ha-icon-button";
import "../../../../../components/ha-icon-button-prev";
import "../../../../../components/ha-icon";
import "../../../../../components/ha-svg-icon";
import {
updateAreaRegistryEntry,
type AreaRegistryEntry,
} from "../../../../../data/area_registry";
import { buttonLinkStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types";
import { showAreaRegistryDetailDialog } from "../../../../config/areas/show-dialog-area-registry-detail";
import type { LovelaceStrategyEditor } from "../../types";
import type { AreasDashboardStrategyConfig } from "../areas-dashboard-strategy";
import type { AreaStrategyGroup } from "../helpers/areas-strategy-helper";
import {
AREA_STRATEGY_GROUP_ICONS,
AREA_STRATEGY_GROUPS,
getAreaGroupedEntities,
} from "../helpers/areas-strategy-helper";
import type { LovelaceStrategyEditor } from "../../types";
import type { AreasDashboardStrategyConfig } from "../areas-dashboard-strategy";
import { showAreaRegistryDetailDialog } from "../../../../config/areas/show-dialog-area-registry-detail";
import {
updateAreaRegistryEntry,
type AreaRegistryEntry,
} from "../../../../../data/area_registry";
import { buttonLinkStyle } from "../../../../../resources/styles";
import "../../../../../components/ha-areas-floors-display-editor";
@customElement("hui-areas-dashboard-strategy-editor")
export class HuiAreasDashboardStrategyEditor
@@ -58,14 +62,18 @@ export class HuiAreasDashboardStrategyEditor
</div>
<ha-expansion-panel
.header=${this.hass!.localize(
`ui.panel.lovelace.strategy.areas.header`
`ui.panel.lovelace.strategy.areas.sensors`
)}
expanded
outlined
>
<ha-svg-icon
slot="leading-icon"
.path=${mdiThermometerWater}
></ha-svg-icon>
<p>
${this.hass!.localize(
`ui.panel.lovelace.strategy.areas.header_description`,
`ui.panel.lovelace.strategy.areas.sensors_description`,
{
edit_the_area: html`
<button class="link" @click=${this._editArea} .area=${area}>
@@ -120,7 +128,7 @@ export class HuiAreasDashboardStrategyEditor
`;
}
const value = this._config.areas_display;
const value = this._areasFloorsDisplayValue(this._config);
return html`
<ha-areas-floors-display-editor
@@ -129,7 +137,7 @@ export class HuiAreasDashboardStrategyEditor
.label=${this.hass.localize(
"ui.panel.lovelace.editor.strategy.areas.areas_display"
)}
@value-changed=${this._areasDisplayChanged}
@value-changed=${this._areasFloorsDisplayChanged}
expanded
show-navigation-button
@item-display-navigate-clicked=${this._handleAreaNavigate}
@@ -143,6 +151,13 @@ export class HuiAreasDashboardStrategyEditor
}
}
private _areasFloorsDisplayValue = memoizeOne(
(config: AreasDashboardStrategyConfig): AreasFloorsDisplayValue => ({
areas_display: config.areas_display,
floors_display: config.floors_display,
})
);
private _editArea(ev: Event): void {
ev.stopPropagation();
const area = (ev.currentTarget! as any).area as AreaRegistryEntry;
@@ -157,11 +172,11 @@ export class HuiAreasDashboardStrategyEditor
this._area = ev.detail.value;
}
private _areasDisplayChanged(ev: CustomEvent): void {
const value = ev.detail.value as AreasDisplayValue;
private _areasFloorsDisplayChanged(ev: CustomEvent): void {
const value = ev.detail.value as AreasFloorsDisplayValue;
const newConfig: AreasDashboardStrategyConfig = {
...this._config!,
areas_display: value,
...value,
};
fireEvent(this, "config-changed", { config: newConfig });
@@ -213,9 +228,13 @@ export class HuiAreasDashboardStrategyEditor
ha-expansion-panel {
margin-bottom: 8px;
max-width: 600px;
--expansion-panel-summary-padding: 0 16px;
}
ha-expansion-panel [slot="leading-icon"] {
margin-inline-end: 16px;
}
ha-expansion-panel p {
margin: 8px 2px;
margin: 8px 8px 16px 8px;
}
button.link {
color: var(--primary-color);

View File

@@ -3,9 +3,13 @@ import { computeStateName } from "../../../../../common/entity/compute_state_nam
import type { EntityFilterFunc } from "../../../../../common/entity/entity_filter";
import { generateEntityFilter } from "../../../../../common/entity/entity_filter";
import { stripPrefixFromEntityName } from "../../../../../common/entity/strip_prefix_from_entity_name";
import { orderCompare } from "../../../../../common/string/compare";
import {
orderCompare,
stringCompare,
} from "../../../../../common/string/compare";
import type { AreaRegistryEntry } from "../../../../../data/area_registry";
import { areaCompare } from "../../../../../data/area_registry";
import type { FloorRegistryEntry } from "../../../../../data/floor_registry";
import type { LovelaceCardConfig } from "../../../../../data/lovelace/config/card";
import type { HomeAssistant } from "../../../../../types";
import { supportsAlarmModesCardFeature } from "../../../card-features/hui-alarm-modes-card-feature";
@@ -290,4 +294,23 @@ export const getAreas = (
return sortedAreas;
};
export const getFloors = (
entries: HomeAssistant["floors"],
floorsOrder?: string[]
): FloorRegistryEntry[] => {
const floors = Object.values(entries);
const compare = orderCompare(floorsOrder || []);
return floors.sort((floorA, floorB) => {
const order = compare(floorA.floor_id, floorB.floor_id);
if (order !== 0) {
return order;
}
if (floorA.level !== floorB.level) {
return (floorA.level ?? 0) - (floorB.level ?? 0);
}
return stringCompare(floorA.name, floorB.name);
});
};
export const computeAreaPath = (areaId: string): string => `areas-${areaId}`;

View File

@@ -51,7 +51,7 @@ export const haTheme = EditorView.theme({
"&": {
color: "var(--primary-text-color)",
backgroundColor:
"var(--code-editor-background-color, var(--mdc-text-field-fill-color, whitesmoke))",
"var(--code-editor-background-color, var(--card-background-color))",
borderRadius:
"var(--mdc-shape-small, 4px) var(--mdc-shape-small, 4px) 0px 0px",
caretColor: "var(--secondary-text-color)",

View File

@@ -51,7 +51,7 @@
"owner": "Owner",
"system-admin": "Administrators",
"system-users": "Users",
"system-read-only": "Read-Only Users"
"system-read-only": "Read-only users"
},
"config_entry": {
"disabled_by": {
@@ -471,7 +471,7 @@
"radius_meters": "[%key:ui::panel::config::core::section::core::core_config::elevation_meters%]"
},
"selector": {
"options": "Selector Options",
"options": "Selector options",
"types": {
"action": "Action",
"area": "Area",
@@ -480,7 +480,7 @@
"color_temp": "Color temperature",
"condition": "Condition",
"date": "Date",
"datetime": "Date and Time",
"datetime": "Date and time",
"device": "Device",
"duration": "Duration",
"entity": "Entity",
@@ -490,7 +490,7 @@
"media": "Media",
"number": "Number",
"object": "Object",
"color_rgb": "RGB Color",
"color_rgb": "RGB color",
"select": "Select",
"state": "State",
"target": "Target",
@@ -498,7 +498,7 @@
"text": "Text",
"theme": "Theme",
"time": "Time",
"manual": "Manual Entry"
"manual": "Manual entry"
}
},
"template": {
@@ -857,7 +857,7 @@
"cyan": "Cyan",
"teal": "Teal",
"green": "Green",
"light-green": "Light Green",
"light-green": "Light green",
"lime": "Lime",
"yellow": "Yellow",
"amber": "Amber",
@@ -1045,7 +1045,7 @@
"podcast": "Podcast",
"season": "Season",
"track": "Track",
"tv_show": "TV Show",
"tv_show": "TV show",
"url": "URL",
"video": "Video"
},
@@ -2935,7 +2935,7 @@
"name": "Name",
"description": "Description",
"tag_id": "Tag ID",
"tag_id_placeholder": "Autogenerated if left empty",
"tag_id_placeholder": "Auto-generated if left empty",
"delete": "Delete",
"update": "Update",
"create": "Create",
@@ -4490,14 +4490,14 @@
"trace_no_longer_available": "Chosen trace is no longer available",
"enter_downloaded_trace": "Enter downloaded trace",
"tabs": {
"details": "Step Details",
"timeline": "Trace Timeline",
"details": "Step details",
"timeline": "Trace timeline",
"logbook": "Related logbook entries",
"automation_config": "Automation Config",
"step_config": "Step Config",
"changed_variables": "Changed Variables",
"blueprint_config": "Blueprint Config",
"script_config": "Script Config"
"automation_config": "Automation config",
"step_config": "Step config",
"changed_variables": "Changed variables",
"blueprint_config": "Blueprint config",
"script_config": "Script config"
},
"path": {
"choose": "Select a step on the left for more information.",
@@ -4544,7 +4544,7 @@
"caption": "Blueprints",
"description": "Manage blueprints",
"overview": {
"header": "Blueprint Editor",
"header": "Blueprint editor",
"introduction": "The blueprint configuration allows you to import and manage your blueprints.",
"learn_more": "Learn more about using blueprints",
"headers": {
@@ -4601,14 +4601,14 @@
"override_description": "Importing it will override the existing blueprint. If the updated blueprint is not compatible, it can break your automations. Automations will have to be adjusted manually.",
"error_no_url": "Please enter the blueprint address.",
"unsupported_blueprint": "This blueprint is not supported",
"file_name": "Blueprint Path"
"file_name": "Blueprint path"
}
},
"script": {
"caption": "Scripts",
"description": "Execute a sequence of actions",
"picker": {
"header": "Script Editor",
"header": "Script editor",
"introduction": "The script editor allows you to create and edit scripts. Please follow the link below to read the instructions to make sure that you have configured Home Assistant correctly.",
"learn_more": "Learn more about scripts",
"no_scripts": "We couldn't find any scripts",
@@ -4684,7 +4684,7 @@
"field_delete_confirm_title": "Delete field?",
"field_delete_confirm_text": "[%key:ui::panel::config::automation::editor::triggers::delete_confirm_text%]",
"header": "Script: {name}",
"default_name": "New Script",
"default_name": "New script",
"modes": {
"label": "[%key:ui::panel::config::automation::editor::modes::label%]",
"learn_more": "[%key:ui::panel::config::automation::editor::modes::learn_more%]",
@@ -4729,7 +4729,7 @@
"description": "Capture device states and easily recall them later",
"activated": "Activated scene {name}.",
"picker": {
"header": "Scene Editor",
"header": "Scene editor",
"introduction": "The scene editor allows you to create and edit scenes. Please follow the link below to read the instructions to make sure that you have configured Home Assistant correctly.",
"learn_more": "Learn more about scenes",
"pick_scene": "Pick scene to edit",
@@ -4993,7 +4993,7 @@
"other_home_assistant": "Other Home Assistant",
"instance_name": "Instance name",
"instance_version": "Instance version",
"ip_address": "IP Address",
"ip_address": "IP address",
"connected_at": "Connected at",
"obfuscated_ip": {
"show": "Show IP address",
@@ -5128,7 +5128,8 @@
"disabled_entities": "+{count} disabled {count, plural,\n one {entity}\n other {entities}\n}",
"hidden": "Hidden"
},
"confirm_disable_config_entry": "There are no more devices for the config entry {entry_name}, do you want to instead disable the config entry?",
"confirm_disable_config_entry_title": "Disable config entry?",
"confirm_disable_config_entry_message": "There are no more devices for the config entry {name}, do you want to disable the config entry instead?",
"update_device_error": "Updating the device failed",
"disabled": "Disabled",
"data_table": {
@@ -5379,8 +5380,10 @@
"device": {
"enable": "Enable device",
"disable": "Disable device",
"confirm_disable": "Are you sure you want to disable {name}?",
"confirm_disable_title": "Disable device?",
"confirm_disable_message": "Are you sure you want to disable {name} and all of its entities?",
"configure": "Configure device",
"edit": "Edit device",
"delete": "Remove device"
},
"devices": "{count} {count, plural,\n one {device}\n other {devices}\n}",
@@ -5414,7 +5417,7 @@
"via": "Connected via",
"firmware": "Firmware: {version}",
"hardware": "Hardware: {version}",
"version": "Version: {version}",
"version": "Version {version}",
"serial_number": "Serial number: {serial_number}",
"unnamed_entry": "Unnamed entry",
"unknown_via_device": "Unknown device",
@@ -5433,7 +5436,6 @@
}
},
"custom_integration": "Custom integration",
"internal_integration": "Internal integration",
"legacy_integration": "Legacy integration",
"custom_overwrites_core": "Custom integration that replaces a core component",
"depends_on_cloud": "Requires Internet",
@@ -5660,9 +5662,9 @@
},
"dhcp": {
"title": "DHCP discovery",
"mac_address": "MAC Address",
"mac_address": "MAC address",
"hostname": "Hostname",
"ip_address": "IP Address",
"ip_address": "IP address",
"no_devices_found": "No recent DHCP requests found; no matching discoveries detected"
},
"thread": {
@@ -5721,7 +5723,7 @@
"name": "Name",
"type": "Type",
"port": "Port",
"ip_addresses": "IP Addresses",
"ip_addresses": "IP addresses",
"properties": "Properties",
"discovery_information": "Discovery information",
"copy_to_clipboard": "Copy to clipboard",
@@ -6353,7 +6355,7 @@
"title": "Door lock",
"twist_assist": "Twist assist",
"block_to_block": "Block to block",
"auto_relock_time": "Auto relock time",
"auto_relock_time": "Autorelock time",
"hold_release_time": "Hold and release time",
"operation_type": "Operation type",
"operation_types": {
@@ -6524,13 +6526,13 @@
"prefix": "Subnet prefix",
"add_address": "Add address",
"gateway": "Gateway address",
"dns_server": "DNS Server",
"add_dns_server": "Add DNS Server",
"dns_server": "DNS server",
"add_dns_server": "Add DNS server",
"custom_dns": "Custom",
"unsaved": "You have unsaved changes, these will get lost if you change tabs, do you want to continue?",
"failed_to_change": "Failed to change network settings",
"hostname": {
"title": "Host name",
"title": "Hostname",
"description": "The name your instance will have on your network",
"failed_to_set_hostname": "Setting hostname failed"
}
@@ -6547,9 +6549,9 @@
},
"network_adapter": "Network adapter",
"network_adapter_info": "Configure which network adapters integrations will use. A restart is required for these settings to apply.",
"ip_information": "IP Information",
"ip_information": "IP information",
"adapter": {
"auto_configure": "Auto configure",
"auto_configure": "Autoconfigure",
"detected": "Detected",
"adapter": "Adapter"
}
@@ -6558,7 +6560,7 @@
"caption": "Storage",
"description": "{percent_used} used - {free_space} free",
"used_space": "Used space",
"emmc_lifetime_used": "eMMC Lifetime Used",
"emmc_lifetime_used": "eMMC lifetime used",
"disk_metrics": "Disk metrics",
"datadisk": {
"title": "Move data disk",
@@ -6672,8 +6674,8 @@
},
"areas": {
"no_entities": "No entities in this area.",
"header": "Area badges",
"header_description": "To display temperature and humidity sensors in the overview and in the area view, add a sensor to that area and {edit_the_area} to configure related sensors.",
"sensors": "Sensors",
"sensors_description": "To display temperature and humidity sensors in the overview and in the area view, add a sensor to that area and {edit_the_area} to configure related sensors.",
"edit_the_area": "edit the area",
"groups": {
"lights": "Lights",
@@ -6684,7 +6686,8 @@
"actions": "Actions",
"others": "Others"
},
"unassigned_areas": "[%key:ui::panel::config::areas::picker::unassigned_areas%]"
"other_areas": "Other areas",
"areas": "Areas"
}
},
"cards": {
@@ -6908,7 +6911,7 @@
},
"edit_view": {
"header": "View configuration",
"header_name": "{name} View Configuration",
"header_name": "{name} view configuration",
"add": "Add view",
"background": {
"settings": "Background settings",
@@ -7024,7 +7027,7 @@
},
"edit_card": {
"header": "Card configuration",
"typed_header": "{type} Card configuration",
"typed_header": "{type} card configuration",
"pick_card": "Add to dashboard",
"pick_card_title": "Which card would you like to add to {name}",
"toggle_editor": "Toggle editor",
@@ -7094,7 +7097,7 @@
"move_card": {
"header": "Choose a view to move the card to",
"strategy_error_title": "Impossible to move the card",
"strategy_error_text_strategy": "Moving a card to an auto generated view is not supported.",
"strategy_error_text_strategy": "Moving a card to an auto-generated view is not supported.",
"success": "Card moved successfully",
"error": "Error while moving card"
},
@@ -7429,7 +7432,7 @@
},
"light": {
"name": "Light",
"description": "The Light card allows you to change the brightness of the light."
"description": "The Light card allows you to change the brightness of a light."
},
"generic": {
"alt_text": "Alternative text",
@@ -7517,13 +7520,13 @@
"geo_location_sources": "Geolocation sources",
"no_geo_location_sources": "No geolocation sources available",
"appearance": "Appearance",
"theme_mode": "Theme Mode",
"theme_mode": "Theme mode",
"theme_modes": {
"auto": "Auto",
"light": "Light",
"dark": "Dark"
},
"default_zoom": "Default Zoom",
"default_zoom": "Default zoom",
"source": "Source",
"description": "The Map card that allows you to display entities on a map."
},
@@ -7571,7 +7574,7 @@
"picture-elements": {
"name": "Picture elements",
"description": "The Picture elements card is one of the most versatile types of cards. The cards allow you to position icons or text and even actions! On an image based on coordinates.",
"card_options": "Card Options",
"card_options": "Card options",
"elements": "Elements",
"new_element": "Add new element",
"confirm_delete_element": "Are you sure you want to delete the {type} element?",
@@ -7610,7 +7613,7 @@
"none": "None",
"line": "Line"
},
"description": "The Sensor card gives you a quick overview of your sensors state with an optional graph to visualize change over time.",
"description": "The Sensor card gives you a quick overview of a sensor's state with an optional graph to visualize change over time.",
"limit_min": "Minimum value",
"limit_max": "Maximum value"
},
@@ -7620,14 +7623,14 @@
"integration_not_loaded": "This card requires the `todo` integration to be set up.",
"hide_completed": "Hide completed items",
"hide_create": "Hide 'Add item' field",
"display_order": "Display Order",
"display_order": "Display order",
"sort_modes": {
"none": "Default",
"manual": "Manual",
"alpha_asc": "Alphabetical (A-Z)",
"alpha_desc": "Alphabetical (Z-A)",
"duedate_asc": "Due Date (Soonest First)",
"duedate_desc": "Due Date (Latest First)"
"duedate_asc": "Due date (Soonest first)",
"duedate_desc": "Due date (Latest first)"
}
},
"thermostat": {
@@ -7637,7 +7640,7 @@
},
"tile": {
"name": "Tile",
"description": "The tile card gives you a quick overview of your entity. The card allows you to toggle the entity, show the More info dialog or trigger custom actions.",
"description": "The Tile card gives you a quick overview of an entity. The card allows you to toggle the entity, show the More info dialog or trigger custom actions.",
"color": "Color",
"color_helper": "Inactive state (e.g. off, closed) will not be colored.",
"icon_tap_action": "Icon tap behavior",
@@ -7691,7 +7694,7 @@
"badge": {
"entity": {
"name": "Entity",
"description": "The Entity badge gives you a quick overview of your entity.",
"description": "The Entity badge gives you a quick overview of an entity.",
"color": "[%key:ui::panel::lovelace::editor::card::tile::color%]",
"color_helper": "[%key:ui::panel::lovelace::editor::card::tile::color_helper%]",
"show_entity_picture": "Show entity picture",
@@ -8229,14 +8232,14 @@
"confirm_delete_title": "Delete long-lived access token?",
"confirm_delete_text": "Are you sure you want to delete the long-lived access token for {name}?",
"delete_failed": "Failed to delete the access token.",
"create": "Create Token",
"create": "Create token",
"create_failed": "Failed to create the access token.",
"name": "Name",
"prompt_name": "Give the token a name",
"prompt_copy_token": "Copy your access token. It will not be shown again.",
"empty_state": "You have no long-lived access tokens yet.",
"qr_code_image": "QR code for token {name}",
"generate_qr_code": "Generate QR Code"
"generate_qr_code": "Generate QR code"
}
},
"todo": {
@@ -8393,7 +8396,7 @@
"hdmi_input": "HDMI input",
"hdmi_switcher": "HDMI switcher",
"volume": "Volume",
"total_tv_time": "Total TV Time",
"total_tv_time": "Total TV time",
"turn_tv_off": "Turn television off",
"air": "Air"
},
@@ -8663,7 +8666,7 @@
"input_button": "Input buttons",
"input_text": "Input texts",
"input_number": "Input numbers",
"input_datetime": "Input date times",
"input_datetime": "Input datetimes",
"input_select": "Input selects",
"template": "Template entities",
"universal": "Universal media player entities",
@@ -9074,7 +9077,7 @@
},
"capability": {
"stage": {
"title": "Add-on Stage",
"title": "Add-on stage",
"description": "Add-ons can have one of three stages:\n\n{icon_stable} **Stable**: These are add-ons ready to be used in production.\n\n{icon_experimental} **Experimental**: These may contain bugs, and may be unfinished.\n\n{icon_deprecated} **Deprecated**: These add-ons will no longer receive any updates."
},
"rating": {
@@ -9156,8 +9159,8 @@
"description": "This will restart the add-on if it crashes"
},
"auto_update": {
"title": "Auto update",
"description": "Auto update the add-on when there is a new version available"
"title": "Autoupdate",
"description": "Autoupdate the add-on when there is a new version available"
},
"ingress_panel": {
"title": "Show in sidebar",
@@ -9268,7 +9271,7 @@
"addons": "Add-ons",
"dashboard": "Dashboard",
"backups": "Backups",
"store": "Add-on Store",
"store": "Add-on store",
"system": "System"
},
"my": {
@@ -9358,7 +9361,7 @@
"hostname": "Hostname",
"change_hostname": "Change hostname",
"new_hostname": "Please enter a new hostname:",
"ip_address": "IP Address",
"ip_address": "IP address",
"change": "Change",
"operating_system": "Operating system",
"docker_version": "Docker version",
@@ -9410,7 +9413,7 @@
"confirm_password": "Confirm encryption key",
"password_protection": "Password protection",
"enter_password": "Please enter a password.",
"passwords_not_matching": "The passwords does not match",
"passwords_not_matching": "The passwords do not match",
"backup_already_running": "A backup or restore is already running. Creating a new backup is currently not possible, try again later.",
"confirm_restore_partial_backup_title": "Restore partial backup",
"confirm_restore_partial_backup_text": "The backup will be restored. Depending on the size of the backup, this can take up to 45 min. Home Assistant needs to shutdown and the restore progress is running in the background. If it succeeds, Home Assistant will automatically start again.",

178
yarn.lock
View File

@@ -5017,131 +5017,131 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/a11y-base@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/a11y-base@npm:24.8.0"
"@vaadin/a11y-base@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/a11y-base@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/component-base": "npm:~24.7.9"
lit: "npm:^3.0.0"
checksum: 10/67aa4700b9f385aa92ca18e68abaa2fb592336673f2286dd2ef2b5eaba1fb8b882f454590fb68e975d4caf0a8698a953ffddcece943d10f91b960272152db564
checksum: 10/7ea96ca92f292a899e0a911f190d194eb330f2916c2dfdfc5de83771b6f339af2413e8f8f8909ac66b2bd876854cc5e9043484062c817e997ef72fc467af3709
languageName: node
linkType: hard
"@vaadin/combo-box@npm:24.8.0":
version: 24.8.0
resolution: "@vaadin/combo-box@npm:24.8.0"
"@vaadin/combo-box@npm:24.7.9":
version: 24.7.9
resolution: "@vaadin/combo-box@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:^24.8.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/field-base": "npm:^24.8.0"
"@vaadin/input-container": "npm:^24.8.0"
"@vaadin/item": "npm:^24.8.0"
"@vaadin/lit-renderer": "npm:^24.8.0"
"@vaadin/overlay": "npm:^24.8.0"
"@vaadin/vaadin-lumo-styles": "npm:^24.8.0"
"@vaadin/vaadin-material-styles": "npm:^24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:^24.8.0"
"@vaadin/a11y-base": "npm:~24.7.9"
"@vaadin/component-base": "npm:~24.7.9"
"@vaadin/field-base": "npm:~24.7.9"
"@vaadin/input-container": "npm:~24.7.9"
"@vaadin/item": "npm:~24.7.9"
"@vaadin/lit-renderer": "npm:~24.7.9"
"@vaadin/overlay": "npm:~24.7.9"
"@vaadin/vaadin-lumo-styles": "npm:~24.7.9"
"@vaadin/vaadin-material-styles": "npm:~24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:~24.7.9"
lit: "npm:^3.0.0"
checksum: 10/c448e127ec53abfd3beca525518342a6d61ad62874e5c8ed3dea56cab66b7f9e132d40d6727ebe42dad53d0b343d30405ca6d9018d3a3a8b7b96c1f50b6d0133
checksum: 10/cd63ecbb0b8b260907aa5853faac8846f1d8c0d5ace1a7621b896109eb254afe1d68ff8b41d776bb253d04655e01c2905a4c361f1ad917de9dbde30c8cf9a5fd
languageName: node
linkType: hard
"@vaadin/component-base@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/component-base@npm:24.8.0"
"@vaadin/component-base@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/component-base@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/vaadin-development-mode-detector": "npm:^2.0.0"
"@vaadin/vaadin-usage-statistics": "npm:^2.1.0"
lit: "npm:^3.0.0"
checksum: 10/7111877c340af80fceb9042d3a58f7916579b0c6639268fa899bc107f61c357b65154e07247232ca9f922ba3399c43b1176fa2226f4faa1091f51ab11c74c572
checksum: 10/24c11b6d395978b82ff54503dc578ef89ce6b2644d2768f1f25ec058b921ab3f9e3d011bf9a739db30112a40c1f89f61ec2cec41c2c0031a603f3c484c6ead11
languageName: node
linkType: hard
"@vaadin/field-base@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/field-base@npm:24.8.0"
"@vaadin/field-base@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/field-base@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:^24.8.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/a11y-base": "npm:~24.7.9"
"@vaadin/component-base": "npm:~24.7.9"
lit: "npm:^3.0.0"
checksum: 10/3357d43a310464d9c76f10e782ec658ae5af9b5a9308faf6de878e3e110b4c20ebc6af8b7f33954f73cfd0f527798787c1994498675067cc814c01ef0588deeb
checksum: 10/4c93e46621871daace3a202e33e5da0f8021c5f3847675ebc608e813a2c2a466a8f5743288eb591296b5119f2735bb18c754e360928b179221271ecae943f240
languageName: node
linkType: hard
"@vaadin/icon@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/icon@npm:24.8.0"
"@vaadin/icon@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/icon@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/vaadin-lumo-styles": "npm:^24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:^24.8.0"
"@vaadin/component-base": "npm:~24.7.9"
"@vaadin/vaadin-lumo-styles": "npm:~24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:~24.7.9"
lit: "npm:^3.0.0"
checksum: 10/e0a90e694179d59228c32e8e93c89e0cc2ebc9509995d6a24679137086796a116b6de9c7fd2e64cec532445bbb20a9991f958d6482cedbf271d041e611163558
checksum: 10/277156010b88541b7cf473683899c0c2004d049f98a1aeb76555bf0e728663193d273a4224d88a04c1eabefbd6710c7a77f11c5b01c3e1037ef1b95c9c2c5ffc
languageName: node
linkType: hard
"@vaadin/input-container@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/input-container@npm:24.8.0"
"@vaadin/input-container@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/input-container@npm:24.7.9"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/vaadin-lumo-styles": "npm:^24.8.0"
"@vaadin/vaadin-material-styles": "npm:^24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:^24.8.0"
"@vaadin/component-base": "npm:~24.7.9"
"@vaadin/vaadin-lumo-styles": "npm:~24.7.9"
"@vaadin/vaadin-material-styles": "npm:~24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:~24.7.9"
lit: "npm:^3.0.0"
checksum: 10/b9ae6590936f68cfb77d5d4ff29b7acb63c16482059391efd64f72837984df084aeb6f39313adb3ea482496adb6f3d84a3195dd265d59f508ccffcb0d5d7b9a4
checksum: 10/6cc5934626c056178ba35bbe21a4f4094591e40955931630fc7a00c7a3db89be59b6884a75ef956b6f39eab1ced4309bffed9f57f084775b73e5d8b7a27c4ed7
languageName: node
linkType: hard
"@vaadin/item@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/item@npm:24.8.0"
"@vaadin/item@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/item@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:^24.8.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/vaadin-lumo-styles": "npm:^24.8.0"
"@vaadin/vaadin-material-styles": "npm:^24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:^24.8.0"
"@vaadin/a11y-base": "npm:~24.7.9"
"@vaadin/component-base": "npm:~24.7.9"
"@vaadin/vaadin-lumo-styles": "npm:~24.7.9"
"@vaadin/vaadin-material-styles": "npm:~24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:~24.7.9"
lit: "npm:^3.0.0"
checksum: 10/a4eb618e7d204147379732244fc5bf3cdf7420ce168f91e0db9cb2a809fad267af4f54eac117a7fbb287a33489a12c7d4724d3a4e7a7fdd415ac30eb6f3554b5
checksum: 10/d0317af3876686cc9353fe42d582f3b03ebb0d3f7f6c7760f95ac8f8e50b7995abccb1804e1fc2df58265b710eab53a881ed07e52c0a716d4da84e275560c95f
languageName: node
linkType: hard
"@vaadin/lit-renderer@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/lit-renderer@npm:24.8.0"
"@vaadin/lit-renderer@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/lit-renderer@npm:24.7.9"
dependencies:
lit: "npm:^3.0.0"
checksum: 10/f843d389f8f1958ec70d5180535a620e774f90bd3e3e5e77e41c6b89f4820272df2a68a70a5d6d752dbb3078b966985767d8ca079054a5fc0daa95d000524d27
checksum: 10/a2101e428a537537e63be12f151f59fb70ae47778186c26465d3c4513372f8ffa4b8be4824b0b6110c03593bd680bc43ac4825f19190434c1dd63abdda0555f4
languageName: node
linkType: hard
"@vaadin/overlay@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/overlay@npm:24.8.0"
"@vaadin/overlay@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/overlay@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:^24.8.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/vaadin-lumo-styles": "npm:^24.8.0"
"@vaadin/vaadin-material-styles": "npm:^24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:^24.8.0"
"@vaadin/a11y-base": "npm:~24.7.9"
"@vaadin/component-base": "npm:~24.7.9"
"@vaadin/vaadin-lumo-styles": "npm:~24.7.9"
"@vaadin/vaadin-material-styles": "npm:~24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:~24.7.9"
lit: "npm:^3.0.0"
checksum: 10/d26330e761868a682013937c66977b5c6662251afa32df7fed0aea218977c25dc0f24a8d9b96561754b746943563c82c7a91e365cf50f8713a549562d63d9ec7
checksum: 10/6790f954a39782f635312ad29edc939257cc4b3007908986ad4f04102cbc21348627aa5fc38ea63e261890fc1a77cd136e935df8ffda48dce65c090f7df4e438
languageName: node
linkType: hard
@@ -5152,37 +5152,36 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/vaadin-lumo-styles@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/vaadin-lumo-styles@npm:24.8.0"
"@vaadin/vaadin-lumo-styles@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/vaadin-lumo-styles@npm:24.7.9"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/icon": "npm:^24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:^24.8.0"
checksum: 10/14d9c942ed88a9aa4579f0c8b8193d51affe3c0fdff781ecb9fb53aef6746d86317eb372526a15b0723017cd67b16bbb3ed252b01c89faa89bb0fca3d1b19855
"@vaadin/component-base": "npm:~24.7.9"
"@vaadin/icon": "npm:~24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:~24.7.9"
checksum: 10/a75ae75ca18fa4c4257f155e8632625b7379a4654c019e29ad5899fea0997275fb8ff519d0d37516e7d8f29466f449187b21f0d03cbd3d0e0a2b79abedf83e18
languageName: node
linkType: hard
"@vaadin/vaadin-material-styles@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/vaadin-material-styles@npm:24.8.0"
"@vaadin/vaadin-material-styles@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/vaadin-material-styles@npm:24.7.9"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:^24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:^24.8.0"
checksum: 10/87917d5b20a1d77e7e38aff1e5be1d28a52a7c08777a01f44a6198cb4f0904ddf7257b23d622a02d098f38928ae3b168e2f2c81ac2c7b952e8056b4958154692
"@vaadin/component-base": "npm:~24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:~24.7.9"
checksum: 10/642bcd8ce3b696b34c80f35c4fdf95b79a34cc956c3eeb2de06335f6db31b07e80d956af3209e3874d1c0df04ecec20efc3358292b50e0aa495a5f94adf649cd
languageName: node
linkType: hard
"@vaadin/vaadin-themable-mixin@npm:24.8.0, @vaadin/vaadin-themable-mixin@npm:^24.8.0":
version: 24.8.0
resolution: "@vaadin/vaadin-themable-mixin@npm:24.8.0"
"@vaadin/vaadin-themable-mixin@npm:24.7.9, @vaadin/vaadin-themable-mixin@npm:~24.7.9":
version: 24.7.9
resolution: "@vaadin/vaadin-themable-mixin@npm:24.7.9"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
lit: "npm:^3.0.0"
style-observer: "npm:^0.0.8"
checksum: 10/141f8756e3330b9ee4efdd34e2febf832a70cf86802908d7fec589567bd4d3ce2820345cbe39fe5a6315bc6dee84065f781f48842ce864ef0a59589607ba1faa
checksum: 10/167827b3082b2fb1028f4ab036d6503667b20f51d81b5857f75390a0341d78067c13064073268de996b24383b4c7d732c621a617e57357003d32e76d1b464a0c
languageName: node
linkType: hard
@@ -9338,8 +9337,8 @@ __metadata:
"@types/tar": "npm:6.1.13"
"@types/ua-parser-js": "npm:0.7.39"
"@types/webspeechapi": "npm:0.0.29"
"@vaadin/combo-box": "npm:24.8.0"
"@vaadin/vaadin-themable-mixin": "npm:24.8.0"
"@vaadin/combo-box": "npm:24.7.9"
"@vaadin/vaadin-themable-mixin": "npm:24.7.9"
"@vibrant/color": "npm:4.0.0"
"@vitest/coverage-v8": "npm:3.2.4"
"@vue/web-component-wrapper": "npm:1.3.0"
@@ -13883,13 +13882,6 @@ __metadata:
languageName: node
linkType: hard
"style-observer@npm:^0.0.8":
version: 0.0.8
resolution: "style-observer@npm:0.0.8"
checksum: 10/9c72ee12c61d48f64622a625ebff9bc4df009877e7ed9b26cec08e8159f6270f428aeea120f0e7c5567c8bbaa701846528fb5339dbdb930e84f2a66d382aeeb6
languageName: node
linkType: hard
"superstruct@npm:2.0.2":
version: 2.0.2
resolution: "superstruct@npm:2.0.2"