20240705.0 (#21306)

This commit is contained in:
Bram Kragten 2024-07-05 13:40:27 +02:00 committed by GitHub
commit 895333aa05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 632 additions and 438 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,7 +1,7 @@
import { convertEntities } from "../../../../src/fake_data/entity";
import { DemoConfig } from "../types";
export const demoEntitiesSections: DemoConfig["entities"] = () =>
export const demoEntitiesSections: DemoConfig["entities"] = (localize) =>
convertEntities({
"cover.living_room_garden_shutter": {
entity_id: "cover.living_room_garden_shutter",
@ -113,11 +113,30 @@ export const demoEntitiesSections: DemoConfig["entities"] = () =>
},
"media_player.living_room_nest_mini": {
entity_id: "media_player.living_room_nest_mini",
state: "off",
state: "on",
attributes: {
device_class: "speaker",
friendly_name: "Living room Nest Mini",
supported_features: 152461,
volume_level: 0.18,
is_volume_muted: false,
media_content_type: "music",
media_duration: 300,
media_position: 0,
media_position_updated_at: new Date(
// 23 seconds in
new Date().getTime() - 23000
).toISOString(),
media_title: "I Wasn't Born To Follow",
media_artist: "The Byrds",
media_album_name: "The Notorious Byrd Brothers",
source_list: ["It's A Party", "Radio HSL", "Retro 70s and 80s"],
shuffle: false,
night_sound: false,
speech_enhance: false,
friendly_name: localize(
"ui.panel.page-demo.config.sections.entities.media_player.living_room_nest_mini"
),
entity_picture: "/assets/sections/images/media_player_family_room.jpg",
supported_features: 64063,
},
},
"cover.kitchen_shutter": {
@ -168,8 +187,27 @@ export const demoEntitiesSections: DemoConfig["entities"] = () =>
state: "on",
attributes: {
device_class: "speaker",
friendly_name: "Kitchen Nest Audio",
supported_features: 152461,
volume_level: 0.18,
is_volume_muted: false,
media_content_type: "music",
media_duration: 300,
media_position: 0,
media_position_updated_at: new Date(
// 23 seconds in
new Date().getTime() - 23000
).toISOString(),
media_title: "I Wasn't Born To Follow",
media_artist: "The Byrds",
media_album_name: "The Notorious Byrd Brothers",
source_list: ["It's A Party", "Radio HSL", "Retro 70s and 80s"],
shuffle: false,
night_sound: false,
speech_enhance: false,
friendly_name: localize(
"ui.panel.page-demo.config.sections.entities.media_player.kitchen_nest_audio"
),
entity_picture: "/assets/sections/images/media_player_family_room.jpg",
supported_features: 64063,
},
},
"binary_sensor.tesla_wall_connector_vehicle_connected": {
@ -333,8 +371,28 @@ export const demoEntitiesSections: DemoConfig["entities"] = () =>
entity_id: "media_player.study_nest_hub",
state: "off",
attributes: {
friendly_name: "Study Nest Hub",
supported_features: 152461,
device_class: "speaker",
volume_level: 0.18,
is_volume_muted: false,
media_content_type: "music",
media_duration: 300,
media_position: 0,
media_position_updated_at: new Date(
// 23 seconds in
new Date().getTime() - 23000
).toISOString(),
media_title: "I Wasn't Born To Follow",
media_artist: "The Byrds",
media_album_name: "The Notorious Byrd Brothers",
source_list: ["It's A Party", "Radio HSL", "Retro 70s and 80s"],
shuffle: false,
night_sound: false,
speech_enhance: false,
friendly_name: localize(
"ui.panel.page-demo.config.sections.entities.media_player.study_nest_hub"
),
entity_picture: "/assets/sections/images/media_player_family_room.jpg",
supported_features: 64063,
},
},
"sensor.standing_desk_height": {

View File

@ -1,7 +1,7 @@
import { isFrontpageEmbed } from "../../util/is_frontpage";
import { DemoConfig } from "../types";
export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
export const demoLovelaceSections: DemoConfig["lovelace"] = (localize) => ({
title: "Home Assistant Demo",
views: [
{
@ -14,7 +14,7 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
? []
: [
{
title: "Welcome 👋",
title: `${localize("ui.panel.page-demo.config.sections.titles.welcome")} 👋`,
cards: [{ type: "custom:ha-demo-card" }],
},
]),
@ -53,10 +53,9 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
{
type: "tile",
entity: "media_player.living_room_nest_mini",
name: "Nest Mini",
},
],
title: "🛋️ Living room ",
title: `🛋️ ${localize("ui.panel.page-demo.config.sections.titles.living_room")} `,
},
{
type: "grid",
@ -89,10 +88,9 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
{
type: "tile",
entity: "media_player.kitchen_nest_audio",
name: "Nest Audio",
},
],
title: "👩‍🍳 Kitchen",
title: `👩‍🍳 ${localize("ui.panel.page-demo.config.sections.titles.kitchen")}`,
},
{
type: "grid",
@ -134,7 +132,7 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
color: "dark-grey",
},
],
title: "⚡️ Energy",
title: `⚡️ ${localize("ui.panel.page-demo.config.sections.titles.energy")}`,
},
{
type: "grid",
@ -171,7 +169,7 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
state_content: ["preset_mode", "current_temperature"],
},
],
title: "🌤️ Climate",
title: `🌤️ ${localize("ui.panel.page-demo.config.sections.titles.climate")}`,
},
{
type: "grid",
@ -189,7 +187,6 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
{
type: "tile",
entity: "media_player.study_nest_hub",
name: "Nest Hub",
},
{
type: "tile",
@ -199,7 +196,7 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
icon: "mdi:desk",
},
],
title: "🧑‍💻 Study",
title: `🧑‍💻 ${localize("ui.panel.page-demo.config.sections.titles.study")}`,
},
{
type: "grid",
@ -233,7 +230,7 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
name: "Illuminance",
},
],
title: "🌳 Outdoor",
title: `🌳 ${localize("ui.panel.page-demo.config.sections.titles.outdoor")}`,
},
{
type: "grid",
@ -263,7 +260,7 @@ export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
icon: "mdi:home-assistant",
},
],
title: "🎉 Updates",
title: `🎉 ${localize("ui.panel.page-demo.config.sections.titles.updates")}`,
},
],
},

View File

@ -1,5 +1,55 @@
import { convertEntities } from "../../../src/fake_data/entity";
export const mapEntities = () =>
convertEntities({
"zone.home": {
entity_id: "zone.home",
state: "zoning",
attributes: {
hidden: true,
latitude: 52.3631339,
longitude: 4.8903147,
radius: 200,
friendly_name: "Home",
icon: "hademo:home",
},
},
"zone.uva": {
entity_id: "zone.buckhead",
state: "zoning",
attributes: {
hidden: true,
radius: 400,
friendly_name: "UvA",
icon: "hademo:school",
latitude: 52.3558182,
longitude: 4.9535376,
},
},
"person.arsaboo": {
entity_id: "person.arsaboo",
state: "not_home",
attributes: {
radius: 50,
friendly_name: "Arsaboo",
latitude: 52.3579946,
longitude: 4.8664597,
entity_picture: "/assets/arsaboo/images/arsaboo.jpg",
},
},
"person.melody": {
entity_id: "person.melody",
state: "not_home",
attributes: {
radius: 50,
friendly_name: "Melody",
latitude: 52.3408927,
longitude: 4.8711073,
entity_picture: "/assets/arsaboo/images/melody.jpg",
},
},
});
export const energyEntities = () =>
convertEntities({
"sensor.grid_fossil_fuel_percentage": {

View File

@ -7,16 +7,25 @@ import {
} from "../configs/demo-configs";
import "../custom-cards/cast-demo-row";
import "../custom-cards/ha-demo-card";
import { mapEntities } from "./entities";
export const mockLovelace = (
hass: MockHomeAssistant,
localizePromise: Promise<LocalizeFunc>
) => {
hass.mockWS("lovelace/config", () =>
Promise.all([selectedDemoConfig, localizePromise]).then(
hass.mockWS("lovelace/config", ({ url_path }) => {
if (url_path === "map") {
hass.addEntities(mapEntities());
return {
strategy: {
type: "map",
},
};
}
return Promise.all([selectedDemoConfig, localizePromise]).then(
([config, localize]) => config.lovelace(localize)
)
);
);
});
hass.mockWS("lovelace/config/save", () => Promise.resolve());
hass.mockWS("lovelace/resources", () => Promise.resolve([]));

View File

@ -3,13 +3,16 @@ title: When to use remove, delete, add and create
subtitle: The difference between remove/delete and add/create.
---
# Remove vs Delete
# Removing or deleting content
Remove and Delete are quite similar, but can be frustrating if used inconsistently.
_Remove_ and _Delete_ are quite similar, but can be frustrating if used inconsistently.
- Remove refers to an action that can be restored or reapplied.
- Delete refers to a permanent, non-recoverable action.
## Remove
Take away and set aside, but kept in existence.
The term _Remove_ should always be used when an item/setting or content is to be removed or disassociated, but the action can be reversed or reapplied.
For example:
@ -22,7 +25,7 @@ For example:
## Delete
Erase, rendered nonexistent or nonrecoverable.
The term _Delete_ should always be used to refer to any action that will cause the permanent deletion of an item/setting or content.
For example:

View File

@ -33,7 +33,7 @@
"@codemirror/legacy-modes": "6.4.0",
"@codemirror/search": "6.5.6",
"@codemirror/state": "6.4.1",
"@codemirror/view": "6.28.2",
"@codemirror/view": "6.28.3",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.12.5",
"@formatjs/intl-displaynames": "6.6.8",
@ -157,7 +157,7 @@
"@babel/preset-typescript": "7.24.7",
"@bundle-stats/plugin-webpack-filter": "4.13.3",
"@koa/cors": "5.0.0",
"@lokalise/node-api": "12.5.0",
"@lokalise/node-api": "12.6.0",
"@octokit/auth-oauth-device": "7.1.1",
"@octokit/plugin-retry": "7.1.1",
"@octokit/rest": "21.0.0",
@ -185,8 +185,8 @@
"@types/tar": "6.1.13",
"@types/ua-parser-js": "0.7.39",
"@types/webspeechapi": "0.0.29",
"@typescript-eslint/eslint-plugin": "7.14.1",
"@typescript-eslint/parser": "7.14.1",
"@typescript-eslint/eslint-plugin": "7.15.0",
"@typescript-eslint/parser": "7.15.0",
"@web/dev-server": "0.1.38",
"@web/dev-server-rollup": "0.4.1",
"babel-loader": "9.1.3",
@ -237,7 +237,7 @@
"terser-webpack-plugin": "5.3.10",
"transform-async-modules-webpack-plugin": "1.1.1",
"ts-lit-plugin": "2.0.2",
"typescript": "5.5.2",
"typescript": "5.5.3",
"webpack": "5.92.1",
"webpack-cli": "5.1.4",
"webpack-dev-server": "5.0.4",

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20240703.0"
version = "20240705.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"

View File

@ -34,6 +34,7 @@ import type { HaCheckbox } from "../ha-checkbox";
import "../ha-svg-icon";
import "../search-input";
import { filterData, sortData } from "./sort-filter";
import { LocalizeFunc } from "../../common/translations/localize";
export interface RowClickedEvent {
id: string;
@ -110,6 +111,8 @@ const UNDEFINED_GROUP_KEY = "zzzzz_undefined";
export class HaDataTable extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public localizeFunc?: LocalizeFunc;
@property({ type: Boolean }) public narrow = false;
@property({ type: Object }) public columns: DataTableColumnContainer = {};
@ -317,6 +320,8 @@ export class HaDataTable extends LitElement {
);
protected render() {
const localize = this.localizeFunc || this.hass.localize;
const columns = this._sortedColumns(this.columns, this.columnOrder);
const renderRow = (row: DataTableRowData, index: number) =>
@ -436,7 +441,7 @@ export class HaDataTable extends LitElement {
<div class="mdc-data-table__row" role="row">
<div class="mdc-data-table__cell grows center" role="cell">
${this.noDataText ||
this.hass.localize("ui.components.data-table.no-data")}
localize("ui.components.data-table.no-data")}
</div>
</div>
</div>
@ -619,6 +624,8 @@ export class HaDataTable extends LitElement {
return;
}
const localize = this.localizeFunc || this.hass.localize;
if (this.appendRow || this.hasFab || this.groupColumn) {
let items = [...data];
@ -672,7 +679,7 @@ export class HaDataTable extends LitElement {
>
</ha-icon-button>
${groupName === UNDEFINED_GROUP_KEY
? this.hass.localize("ui.components.data-table.ungrouped")
? localize("ui.components.data-table.ungrouped")
: groupName || ""}
</div>`,
});

View File

@ -10,7 +10,7 @@ import { HomeAssistant } from "../types";
import { conditionalClamp } from "../common/number/clamp";
type GridSizeValue = {
rows?: number;
rows?: number | "auto";
columns?: number;
};
@ -47,6 +47,16 @@ export class HaGridSizeEditor extends LitElement {
this.columnMin !== undefined && this.columnMin === this.columnMax;
const disabledRows =
this.rowMin !== undefined && this.rowMin === this.rowMax;
const autoHeight = this._localValue?.rows === "auto";
const rowMin = this.rowMin ?? 1;
const rowMax = this.rowMax ?? this.rows;
const columnMin = this.columnMin ?? 1;
const columnMax = this.columnMax ?? this.columns;
const rowValue = autoHeight ? rowMin : this._localValue?.rows;
const columnValue = this._localValue?.columns;
return html`
<div class="grid">
<ha-grid-layout-slider
@ -54,24 +64,25 @@ export class HaGridSizeEditor extends LitElement {
"ui.components.grid-size-picker.columns"
)}
id="columns"
.min=${this.columnMin ?? 1}
.max=${this.columnMax ?? this.columns}
.min=${columnMin}
.max=${columnMax}
.range=${this.columns}
.value=${this.value?.columns}
.value=${columnValue}
@value-changed=${this._valueChanged}
@slider-moved=${this._sliderMoved}
.disabled=${disabledColumns}
></ha-grid-layout-slider>
<ha-grid-layout-slider
aria-label=${this.hass.localize(
"ui.components.grid-size-picker.rows"
)}
id="rows"
.min=${this.rowMin ?? 1}
.max=${this.rowMax ?? this.rows}
.min=${rowMin}
.max=${rowMax}
.range=${this.rows}
vertical
.value=${this.value?.rows}
.value=${rowValue}
@value-changed=${this._valueChanged}
@slider-moved=${this._sliderMoved}
.disabled=${disabledRows}
@ -97,8 +108,8 @@ export class HaGridSizeEditor extends LitElement {
style=${styleMap({
"--total-rows": this.rows,
"--total-columns": this.columns,
"--rows": this._localValue?.rows,
"--columns": this._localValue?.columns,
"--rows": rowValue,
"--columns": columnValue,
})}
>
<div>
@ -215,10 +226,6 @@ export class HaGridSizeEditor extends LitElement {
opacity: 0.2;
cursor: pointer;
}
.preview .cell[disabled] {
opacity: 0.05;
cursor: initial;
}
.selected {
pointer-events: none;
}

View File

@ -1,9 +1,11 @@
import { MdMenuItem } from "@material/web/menu/menu-item";
import { css } from "lit";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
@customElement("ha-menu-item")
export class HaMenuItem extends MdMenuItem {
@property({ attribute: false }) clickAction?: (item?: HTMLElement) => void;
static override styles = [
...super.styles,
css`

View File

@ -1,9 +1,30 @@
import { MdMenu } from "@material/web/menu/menu";
import type { CloseMenuEvent } from "@material/web/menu/menu";
import {
CloseReason,
KeydownCloseKey,
} from "@material/web/menu/internal/controllers/shared";
import { css } from "lit";
import { customElement } from "lit/decorators";
import type { HaMenuItem } from "./ha-menu-item";
@customElement("ha-menu")
export class HaMenu extends MdMenu {
connectedCallback(): void {
super.connectedCallback();
this.addEventListener("close-menu", this._handleCloseMenu);
}
private _handleCloseMenu(ev: CloseMenuEvent) {
if (
ev.detail.reason.kind === CloseReason.KEYDOWN &&
ev.detail.reason.key === KeydownCloseKey.ESCAPE
) {
return;
}
(ev.detail.initiator as HaMenuItem).clickAction?.(ev.detail.initiator);
}
static override styles = [
...super.styles,
css`
@ -18,4 +39,8 @@ declare global {
interface HTMLElementTagNameMap {
"ha-menu": HaMenu;
}
interface HTMLElementEventMap {
"close-menu": CloseMenuEvent;
}
}

View File

@ -325,7 +325,7 @@ export class MoreInfoDialog extends LitElement {
></ha-icon-button>
`
: nothing}
${isAdmin
${!__DEMO__ && isAdmin
? html`
<ha-icon-button
slot="actionItems"

View File

@ -75,11 +75,13 @@ export class MoreInfoHistory extends LitElement {
<div class="title">
${this.hass.localize("ui.dialogs.more_info_control.history")}
</div>
<a href=${this._showMoreHref} @click=${this._close}
>${this.hass.localize(
"ui.dialogs.more_info_control.show_more"
)}</a
>
${__DEMO__
? nothing
: html`<a href=${this._showMoreHref} @click=${this._close}
>${this.hass.localize(
"ui.dialogs.more_info_control.show_more"
)}</a
>`}
</div>
${this._error
? html`<div class="errors">${this._error}</div>`

View File

@ -66,10 +66,10 @@ export const demoPanels: Panels = {
// url_path: "history",
// },
map: {
component_name: "map",
component_name: "lovelace",
icon: "hass:tooltip-account",
title: "map",
config: null,
config: { mode: "storage" },
url_path: "map",
},
energy: {

View File

@ -430,6 +430,7 @@ export class HaTabsSubpageDataTable extends LitElement {
: ""}
<ha-data-table
.hass=${this.hass}
.localize=${localize}
.narrow=${this.narrow}
.columns=${this.columns}
.data=${this.data}
@ -575,10 +576,9 @@ export class HaTabsSubpageDataTable extends LitElement {
</div>
<div slot="primaryAction">
<ha-button @click=${this._toggleFilters}>
${this.hass.localize(
"ui.components.subpage-data-table.show_results",
{ number: this.data.length }
)}
${localize("ui.components.subpage-data-table.show_results", {
number: this.data.length,
})}
</ha-button>
</div>
</ha-dialog>`

View File

@ -68,6 +68,7 @@ import "../../../components/ha-icon-overflow-menu";
import "../../../components/ha-menu";
import type { HaMenu } from "../../../components/ha-menu";
import "../../../components/ha-menu-item";
import type { HaMenuItem } from "../../../components/ha-menu-item";
import "../../../components/ha-sub-menu";
import "../../../components/ha-svg-icon";
import { createAreaRegistryEntry } from "../../../data/area_registry";
@ -826,7 +827,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
</ha-fab>
</hass-tabs-subpage-data-table>
<ha-menu id="overflow-menu" positioning="fixed">
<ha-menu-item @click=${this._showInfo}>
<ha-menu-item .clickAction=${this._showInfo}>
<ha-svg-icon
.path=${mdiInformationOutline}
slot="start"
@ -836,7 +837,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
</div>
</ha-menu-item>
<ha-menu-item @click=${this._showSettings}>
<ha-menu-item .clickAction=${this._showSettings}>
<ha-svg-icon .path=${mdiCog} slot="start"></ha-svg-icon>
<div slot="headline">
${this.hass.localize(
@ -844,7 +845,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
)}
</div>
</ha-menu-item>
<ha-menu-item @click=${this._editCategory}>
<ha-menu-item .clickAction=${this._editCategory}>
<ha-svg-icon .path=${mdiTag} slot="start"></ha-svg-icon>
<div slot="headline">
${this.hass.localize(
@ -852,13 +853,13 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
)}
</div>
</ha-menu-item>
<ha-menu-item @click=${this._runActions}>
<ha-menu-item .clickAction=${this._runActions}>
<ha-svg-icon .path=${mdiPlay} slot="start"></ha-svg-icon>
<div slot="headline">
${this.hass.localize("ui.panel.config.automation.editor.run")}
</div>
</ha-menu-item>
<ha-menu-item @click=${this._showTrace}>
<ha-menu-item .clickAction=${this._showTrace}>
<ha-svg-icon .path=${mdiTransitConnection} slot="start"></ha-svg-icon>
<div slot="headline">
${this.hass.localize(
@ -867,13 +868,13 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
</div>
</ha-menu-item>
<md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._duplicate}>
<ha-menu-item .clickAction=${this._duplicate}>
<ha-svg-icon .path=${mdiContentDuplicate} slot="start"></ha-svg-icon>
<div slot="headline">
${this.hass.localize("ui.panel.config.automation.picker.duplicate")}
</div>
</ha-menu-item>
<ha-menu-item @click=${this._toggle}>
<ha-menu-item .clickAction=${this._toggle}>
<ha-svg-icon
.path=${
this._overflowAutomation?.state === "off"
@ -892,7 +893,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
}
</div>
</ha-menu-item>
<ha-menu-item @click=${this._deleteConfirm} class="warning">
<ha-menu-item .clickAction=${this._deleteConfirm} class="warning">
<ha-svg-icon .path=${mdiDelete} slot="start"></ha-svg-icon>
<div slot="headline">
${this.hass.localize("ui.panel.config.automation.picker.delete")}
@ -1055,28 +1056,32 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
this._applyFilters();
}
private _showInfo(ev) {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _showInfo = (item: HaMenuItem) => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
fireEvent(this, "hass-more-info", { entityId: automation.entity_id });
}
};
private _showSettings(ev) {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _showSettings = (item: HaMenuItem) => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
fireEvent(this, "hass-more-info", {
entityId: automation.entity_id,
view: "settings",
});
}
};
private _runActions(ev) {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _runActions = (item: HaMenuItem) => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
triggerAutomationActions(this.hass, automation.entity_id);
}
};
private _editCategory(ev) {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _editCategory = (item: HaMenuItem) => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
const entityReg = this._entityReg.find(
(reg) => reg.entity_id === automation.entity_id
@ -1096,10 +1101,11 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
scope: "automation",
entityReg,
});
}
};
private _showTrace(ev) {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _showTrace = (item: HaMenuItem) => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
if (!automation.attributes.id) {
showAlertDialog(this, {
@ -1112,19 +1118,21 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
navigate(
`/config/automation/trace/${encodeURIComponent(automation.attributes.id)}`
);
}
};
private async _toggle(ev): Promise<void> {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _toggle = async (item: HaMenuItem): Promise<void> => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
const service = automation.state === "off" ? "turn_on" : "turn_off";
await this.hass.callService("automation", service, {
entity_id: automation.entity_id,
});
}
};
private async _deleteConfirm(ev) {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _deleteConfirm = async (item: HaMenuItem) => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
showConfirmationDialog(this, {
title: this.hass.localize(
@ -1139,7 +1147,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
confirm: () => this._delete(automation),
destructive: true,
});
}
};
private async _delete(automation) {
try {
@ -1159,8 +1167,9 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
}
}
private async _duplicate(ev) {
const automation = ev.currentTarget.parentElement.anchorElement.automation;
private _duplicate = async (item: HaMenuItem) => {
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!
.automation;
try {
const config = await fetchAutomationFileConfig(
@ -1184,7 +1193,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
),
});
}
}
};
private _showHelp() {
showAlertDialog(this, {

View File

@ -1,6 +1,5 @@
import { consume } from "@lit-labs/context";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import "@material/mwc-list/mwc-list-item";
import {
mdiCog,
mdiDelete,
@ -10,8 +9,6 @@ import {
mdiPencil,
mdiPlusCircle,
} from "@mdi/js";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
import {
CSSResultGroup,
LitElement,
@ -24,7 +21,7 @@ import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { SENSOR_ENTITIES, ASSIST_ENTITIES } from "../../../common/const";
import { ASSIST_ENTITIES, SENSOR_ENTITIES } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
@ -77,7 +74,6 @@ import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
import { fileDownload } from "../../../util/file_download";
import "../../logbook/ha-logbook";
import "../ha-config-section";
import "./device-detail/ha-device-entities-card";
import "./device-detail/ha-device-info-card";
import "./device-detail/ha-device-via-devices-card";
@ -665,269 +661,235 @@ export class HaConfigDevicePage extends LitElement {
`
: "";
return html`
<hass-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.header=${deviceName}
>
<ha-icon-button
slot="toolbar-icon"
.path=${mdiPencil}
@click=${this._showSettings}
.label=${this.hass.localize(
"ui.panel.config.devices.edit_settings"
)}
></ha-icon-button>
<div class="container">
<div class="header fullwidth">
${
area
? html`<div class="header-name">
<a href="/config/areas/area/${area.area_id}"
>${this.hass.localize(
"ui.panel.config.integrations.config_entry.area",
{ area: area.name || "Unnamed Area" }
)}</a
>
</div>`
: ""
}
<div class="header-right">
${
battery &&
(batteryDomain === "binary_sensor" ||
!isNaN(battery.state as any))
? html`
<div class="battery">
${batteryDomain === "sensor"
? this.hass.formatEntityState(battery)
: nothing}
<ha-battery-icon
.hass=${this.hass}
.batteryStateObj=${battery}
.batteryChargingStateObj=${batteryChargingState}
></ha-battery-icon>
</div>
`
: ""
}
${
integrations.length
? html`
<img
alt=${domainToName(
this.hass.localize,
integrations[0].domain
)}
src=${brandsUrl({
domain: integrations[0].domain,
type: "logo",
darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
@load=${this._onImageLoad}
@error=${this._onImageError}
/>
`
: ""
}
</div>
return html` <hass-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.header=${deviceName}
>
<ha-icon-button
slot="toolbar-icon"
.path=${mdiPencil}
@click=${this._showSettings}
.label=${this.hass.localize("ui.panel.config.devices.edit_settings")}
></ha-icon-button>
<div class="container">
<div class="header fullwidth">
${area
? html`<div class="header-name">
<a href="/config/areas/area/${area.area_id}"
>${this.hass.localize(
"ui.panel.config.integrations.config_entry.area",
{ area: area.name || "Unnamed Area" }
)}</a
>
</div>`
: ""}
<div class="header-right">
${battery &&
(batteryDomain === "binary_sensor" || !isNaN(battery.state as any))
? html`
<div class="battery">
${batteryDomain === "sensor"
? this.hass.formatEntityState(battery)
: nothing}
<ha-battery-icon
.hass=${this.hass}
.batteryStateObj=${battery}
.batteryChargingStateObj=${batteryChargingState}
></ha-battery-icon>
</div>
`
: ""}
${integrations.length
? html`
<img
alt=${domainToName(
this.hass.localize,
integrations[0].domain
)}
src=${brandsUrl({
domain: integrations[0].domain,
type: "logo",
darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
@load=${this._onImageLoad}
@error=${this._onImageError}
/>
`
: ""}
</div>
<div class="column">
${
this._deviceAlerts?.length
? html`
<div>
${this._deviceAlerts.map(
(alert) => html`
<ha-alert .alertType=${alert.level}>
${alert.text}
</ha-alert>
`
)}
</div>
</div>
<div class="column">
${this._deviceAlerts?.length
? html`
<div>
${this._deviceAlerts.map(
(alert) => html`
<ha-alert .alertType=${alert.level}>
${alert.text}
</ha-alert>
`
: ""
}
<ha-device-info-card
.hass=${this.hass}
.device=${device}
>
${deviceInfo}
${
firstDeviceAction || actions.length
? html`
<div class="card-actions" slot="actions">
<div>
<a
href=${ifDefined(firstDeviceAction!.href)}
rel=${ifDefined(
firstDeviceAction!.target
? "noreferrer"
: undefined
)}
target=${ifDefined(firstDeviceAction!.target)}
>
<mwc-button
class=${ifDefined(firstDeviceAction!.classes)}
.action=${firstDeviceAction!.action}
)}
</div>
`
: ""}
<ha-device-info-card .hass=${this.hass} .device=${device}>
${deviceInfo}
${firstDeviceAction || actions.length
? html`
<div class="card-actions" slot="actions">
<div>
<a
href=${ifDefined(firstDeviceAction!.href)}
rel=${ifDefined(
firstDeviceAction!.target ? "noreferrer" : undefined
)}
target=${ifDefined(firstDeviceAction!.target)}
>
<mwc-button
class=${ifDefined(firstDeviceAction!.classes)}
.action=${firstDeviceAction!.action}
@click=${this._deviceActionClicked}
graphic="icon"
>
${firstDeviceAction!.label}
${firstDeviceAction!.icon
? html`
<ha-svg-icon
class=${ifDefined(firstDeviceAction!.classes)}
.path=${firstDeviceAction!.icon}
slot="graphic"
></ha-svg-icon>
`
: ""}
${firstDeviceAction!.trailingIcon
? html`
<ha-svg-icon
.path=${firstDeviceAction!.trailingIcon}
slot="trailingIcon"
></ha-svg-icon>
`
: ""}
</mwc-button>
</a>
</div>
${actions.length
? html`
<ha-button-menu>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
${actions.map((deviceAction) => {
const listItem = html`<mwc-list-item
class=${ifDefined(deviceAction.classes)}
.action=${deviceAction.action}
@click=${this._deviceActionClicked}
graphic="icon"
.hasMeta=${Boolean(deviceAction.trailingIcon)}
>
${firstDeviceAction!.label}
${firstDeviceAction!.icon
${deviceAction.label}
${deviceAction.icon
? html`
<ha-svg-icon
class=${ifDefined(
firstDeviceAction!.classes
)}
.path=${firstDeviceAction!.icon}
class=${ifDefined(deviceAction.classes)}
.path=${deviceAction.icon}
slot="graphic"
></ha-svg-icon>
`
: ""}
${firstDeviceAction!.trailingIcon
${deviceAction.trailingIcon
? html`
<ha-svg-icon
.path=${firstDeviceAction!.trailingIcon}
slot="trailingIcon"
slot="meta"
.path=${deviceAction.trailingIcon}
></ha-svg-icon>
`
: ""}
</mwc-button>
</a>
</div>
${actions.length
? html`
<ha-button-menu>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize(
"ui.common.menu"
</mwc-list-item>`;
return deviceAction.href
? html`<a
href=${deviceAction.href}
target=${ifDefined(deviceAction.target)}
rel=${ifDefined(
deviceAction.target
? "noreferrer"
: undefined
)}
.path=${mdiDotsVertical}
></ha-icon-button>
${actions.map((deviceAction) => {
const listItem = html`<mwc-list-item
class=${ifDefined(deviceAction.classes)}
.action=${deviceAction.action}
@click=${this._deviceActionClicked}
graphic="icon"
.hasMeta=${Boolean(
deviceAction.trailingIcon
)}
>
${deviceAction.label}
${deviceAction.icon
? html`
<ha-svg-icon
class=${ifDefined(
deviceAction.classes
)}
.path=${deviceAction.icon}
slot="graphic"
></ha-svg-icon>
`
: ""}
${deviceAction.trailingIcon
? html`
<ha-svg-icon
slot="meta"
.path=${deviceAction.trailingIcon}
></ha-svg-icon>
`
: ""}
</mwc-list-item>`;
return deviceAction.href
? html`<a
href=${deviceAction.href}
target=${ifDefined(
deviceAction.target
)}
rel=${ifDefined(
deviceAction.target
? "noreferrer"
: undefined
)}
>${listItem}
</a>`
: listItem;
})}
</ha-button-menu>
`
: ""}
</div>
`
: ""
}
</ha-device-info-card>
${!this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
</div>
<div class="column">
${(
[
"control",
"sensor",
"notify",
"event",
"assist",
"config",
"diagnostic",
] as const
).map((category) =>
// Make sure we render controls if no other cards will be rendered
entitiesByCategory[category].length > 0 ||
(entities.length === 0 && category === "control")
? html`
<ha-device-entities-card
.hass=${this.hass}
.header=${this.hass.localize(
`ui.panel.config.devices.entities.${category}`
)}
.deviceName=${deviceName}
.entities=${entitiesByCategory[category]}
.showHidden=${device.disabled_by !== null}
>
</ha-device-entities-card>
`
: ""
)}
<ha-device-via-devices-card
.hass=${this.hass}
.deviceId=${this.deviceId}
></ha-device-via-devices-card>
</div>
<div class="column">
${this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
${
isComponentLoaded(this.hass, "logbook")
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize("panel.logbook")}
</h1>
<ha-logbook
.hass=${this.hass}
.time=${this._logbookTime}
.entityIds=${this._entityIds(entities)}
.deviceIds=${this._deviceIdInList(this.deviceId)}
virtualize
narrow
no-icon
></ha-logbook>
</ha-card>
`
: ""
}
</div>
</div>
</ha-config-section>
</hass-subpage> `;
>${listItem}
</a>`
: listItem;
})}
</ha-button-menu>
`
: ""}
</div>
`
: ""}
</ha-device-info-card>
${!this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
</div>
<div class="column">
${(
[
"control",
"sensor",
"notify",
"event",
"assist",
"config",
"diagnostic",
] as const
).map((category) =>
// Make sure we render controls if no other cards will be rendered
entitiesByCategory[category].length > 0 ||
(entities.length === 0 && category === "control")
? html`
<ha-device-entities-card
.hass=${this.hass}
.header=${this.hass.localize(
`ui.panel.config.devices.entities.${category}`
)}
.deviceName=${deviceName}
.entities=${entitiesByCategory[category]}
.showHidden=${device.disabled_by !== null}
>
</ha-device-entities-card>
`
: ""
)}
<ha-device-via-devices-card
.hass=${this.hass}
.deviceId=${this.deviceId}
></ha-device-via-devices-card>
</div>
<div class="column">
${this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
${isComponentLoaded(this.hass, "logbook")
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize("panel.logbook")}
</h1>
<ha-logbook
.hass=${this.hass}
.time=${this._logbookTime}
.entityIds=${this._entityIds(entities)}
.deviceIds=${this._deviceIdInList(this.deviceId)}
virtualize
narrow
no-icon
></ha-logbook>
</ha-card>
`
: ""}
</div>
</div>
</hass-subpage>`;
}
private async _getDiagnosticButtons(requestId: number): Promise<void> {

View File

@ -301,12 +301,13 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
private async _removeTag(selectedTag: Tag) {
if (
!(await showConfirmationDialog(this, {
title: this.hass!.localize("ui.panel.config.tag.confirm_remove_title"),
text: this.hass.localize("ui.panel.config.tag.confirm_remove", {
title: this.hass!.localize("ui.panel.config.tag.confirm_delete_title"),
text: this.hass.localize("ui.panel.config.tag.confirm_delete", {
tag: selectedTag.name || selectedTag.id,
}),
dismissText: this.hass!.localize("ui.common.cancel"),
confirmText: this.hass!.localize("ui.common.remove"),
confirmText: this.hass!.localize("ui.common.delete"),
destructive: true,
}))
) {
return false;

View File

@ -1,17 +1,17 @@
import {
html,
LitElement,
nothing,
css,
CSSResultGroup,
LitElement,
PropertyValues,
css,
html,
nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { HomeAssistant } from "../../../../types";
import "../../components/hui-energy-period-selector";
import { LovelaceCard } from "../../types";
import { EnergyCardBaseConfig } from "../types";
import { hasConfigChanged } from "../../common/has-changed";
import "../../components/hui-energy-period-selector";
import { LovelaceCard, LovelaceLayoutOptions } from "../../types";
import { EnergyCardBaseConfig } from "../types";
@customElement("hui-energy-date-selection-card")
export class HuiEnergyDateSelectionCard
@ -26,6 +26,13 @@ export class HuiEnergyDateSelectionCard
return 1;
}
public getLayoutOptions(): LovelaceLayoutOptions {
return {
grid_rows: 1,
grid_columns: 4,
};
}
public setConfig(config: EnergyCardBaseConfig): void {
this._config = config;
}
@ -57,6 +64,13 @@ export class HuiEnergyDateSelectionCard
static get styles(): CSSResultGroup {
return css`
:host {
ha-card {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
}
.padded {
padding-left: 16px !important;
padding-inline-start: 16px !important;

View File

@ -8,6 +8,7 @@ import {
PropertyValues,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
@ -73,6 +74,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
@property({ attribute: false }) public hass?: HomeAssistant;
@property() public layout?: string;
@state() private _config?: EntityCardConfig;
private _footerElement?: HuiErrorCard | LovelaceHeaderFooter;
@ -132,8 +135,15 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
const colored = stateObj && this.getStateColor(stateObj, this._config);
const fixedFooter =
this.layout === "grid" || this._footerElement !== undefined;
return html`
<ha-card @click=${this._handleClick} tabindex="0">
<ha-card
@click=${this._handleClick}
tabindex="0"
class=${classMap({ "with-fixed-footer": fixedFooter })}
>
<div class="header">
<div class="name" .title=${name}>${name}</div>
<div class="icon">
@ -188,7 +198,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
`
: ""}
</div>
${this._footerElement}
<div class="footer">${this._footerElement}</div>
</ha-card>
`;
}
@ -309,6 +319,16 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
font-size: 18px;
color: var(--secondary-text-color);
}
.with-fixed-footer {
justify-content: flex-start;
}
.with-fixed-footer .footer {
position: absolute;
right: 0;
left: 0;
bottom: 0;
}
`,
];
}

View File

@ -129,6 +129,8 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
overflow: hidden;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
#root {

View File

@ -123,19 +123,21 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
public getLayoutOptions(): LovelaceLayoutOptions {
const grid_columns = 2;
let grid_min_columns = 2;
let grid_rows = 1;
if (this._config?.features?.length) {
const featureHeight = Math.ceil((this._config.features.length * 2) / 3);
grid_rows += featureHeight;
}
if (this._config?.vertical) {
grid_rows!++;
grid_rows++;
grid_min_columns = 1;
}
return {
grid_columns,
grid_rows,
grid_min_rows: grid_rows,
grid_min_columns: grid_columns,
grid_min_columns,
};
}

View File

@ -378,6 +378,9 @@ export class HaGridLayoutSlider extends LitElement {
:host(:disabled) .handle:after {
background: var(--disabled-color);
}
:host(:disabled) .active {
background: var(--disabled-color);
}
.pressed .handle {
transition: none;
}

View File

@ -11,8 +11,10 @@ import "../../../../components/ha-button-menu";
import "../../../../components/ha-grid-size-picker";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-list-item";
import "../../../../components/ha-settings-row";
import "../../../../components/ha-slider";
import "../../../../components/ha-svg-icon";
import "../../../../components/ha-switch";
import "../../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
@ -61,11 +63,13 @@ export class HuiCardLayoutEditor extends LitElement {
this._defaultLayoutOptions
);
const sizeValue = this._gridSizeValue(options);
return html`
<div class="header">
<p class="intro">
${this.hass.localize(
`ui.panel.lovelace.editor.edit_card.layout.explanation`
"ui.panel.lovelace.editor.edit_card.layout.explanation"
)}
</p>
<ha-button-menu
@ -124,7 +128,7 @@ export class HuiCardLayoutEditor extends LitElement {
: html`
<ha-grid-size-picker
.hass=${this.hass}
.value=${this._gridSizeValue(options)}
.value=${sizeValue}
.isDefault=${this._isDefault(this.config.layout_options)}
@value-changed=${this._gridSizeChanged}
.rowMin=${options.grid_min_rows}

View File

@ -26,11 +26,11 @@ const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
export const DEFAULT_GRID_OPTIONS = {
grid_columns: 4,
grid_rows: 1,
grid_rows: "auto",
} as const satisfies LovelaceLayoutOptions;
type GridSizeValue = {
rows?: number;
rows?: number | "auto";
columns?: number;
};

View File

@ -42,7 +42,7 @@ export interface LovelaceBadge extends HTMLElement {
export type LovelaceLayoutOptions = {
grid_columns?: number;
grid_rows?: number;
grid_rows?: number | "auto";
grid_max_columns?: number;
grid_min_columns?: number;
grid_min_rows?: number;

View File

@ -2107,8 +2107,8 @@
"edit": "Edit",
"never_scanned": "Never scanned",
"create_automation": "Create automation with tag",
"confirm_remove_title": "Remove tag?",
"confirm_remove": "Are you sure you want to remove tag {tag}?",
"confirm_delete_title": "Delete tag?",
"confirm_delete": "Are you sure you want to delete tag {tag}?",
"automation_title": "Tag {name} is scanned",
"qr_code_image": "QR code for tag {name}",
"headers": {
@ -6630,7 +6630,24 @@
},
"sections": {
"description": "This dashboard is using the sections view released in Home Assistant 2024.3. Learn more about it in this {blog_post}.",
"description_blog_post": "blog post"
"description_blog_post": "blog post",
"titles": {
"welcome": "Welcome",
"living_room": "Living room",
"study": "Study",
"kitchen": "Kitchen",
"outdoor": "Outdoor",
"energy": "Energy",
"climate": "Climate",
"updates": "Updates"
},
"entities": {
"media_player": {
"living_room_nest_mini": "Nest mini",
"kitchen_nest_audio": "Nest Audio",
"study_nest_hub": "Nest Hub"
}
}
}
}
},

142
yarn.lock
View File

@ -1539,14 +1539,14 @@ __metadata:
languageName: node
linkType: hard
"@codemirror/view@npm:6.28.2, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
version: 6.28.2
resolution: "@codemirror/view@npm:6.28.2"
"@codemirror/view@npm:6.28.3, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
version: 6.28.3
resolution: "@codemirror/view@npm:6.28.3"
dependencies:
"@codemirror/state": "npm:^6.4.0"
style-mod: "npm:^4.1.0"
w3c-keyname: "npm:^2.2.4"
checksum: 10/c4221d6e47112ec3ec20c954deecab4565a8023dfeefabff8ba1801fb67d2965d49c27853310618fd723077ca86564b4bbefa36f0839d9430518f7d0a1cc3e84
checksum: 10/4732786b1afa3730a2c08b3711b335b8da2cb76318c9c4b2aeafd868bb36bfaeec826a18669b3d2d0f408e8012734689085633e4b6c3609cd2385838d79e5bc6
languageName: node
linkType: hard
@ -2221,10 +2221,10 @@ __metadata:
languageName: node
linkType: hard
"@lokalise/node-api@npm:12.5.0":
version: 12.5.0
resolution: "@lokalise/node-api@npm:12.5.0"
checksum: 10/f070847c5dcf450e060c5cc8a92e1b731c9509c85492ac8864a7e49c16e6532d6aaae76cb3f374c356dbf84d72d548a61d40f89afd6d8090cc16a700b069299a
"@lokalise/node-api@npm:12.6.0":
version: 12.6.0
resolution: "@lokalise/node-api@npm:12.6.0"
checksum: 10/966f4d014c12ef91745925cd6e21698ca35db6483ee50b938e1029509d7c37d0a881bdc673f18debd2fedcafade8c2ce22aa39bea53e0861ba5243a2c646921b
languageName: node
linkType: hard
@ -4584,15 +4584,15 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/eslint-plugin@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/eslint-plugin@npm:7.14.1"
"@typescript-eslint/eslint-plugin@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/eslint-plugin@npm:7.15.0"
dependencies:
"@eslint-community/regexpp": "npm:^4.10.0"
"@typescript-eslint/scope-manager": "npm:7.14.1"
"@typescript-eslint/type-utils": "npm:7.14.1"
"@typescript-eslint/utils": "npm:7.14.1"
"@typescript-eslint/visitor-keys": "npm:7.14.1"
"@typescript-eslint/scope-manager": "npm:7.15.0"
"@typescript-eslint/type-utils": "npm:7.15.0"
"@typescript-eslint/utils": "npm:7.15.0"
"@typescript-eslint/visitor-keys": "npm:7.15.0"
graphemer: "npm:^1.4.0"
ignore: "npm:^5.3.1"
natural-compare: "npm:^1.4.0"
@ -4603,44 +4603,44 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/48c815dbb92399965483c93b27816fad576c3b3227b59eebfe5525e24d07b39ec8b0c7459de83865c8d61c818696519f50b229714dd3ed705d5b35973bfcc781
checksum: 10/e6b21687ab9e9dc38eb1b1d90a3ac483f3f5e5e9c49aa8a434a24de016822d65c82b926cda2ae79bac2225bd9495fb04f7aa6afcaad2b09f6129fd8014fbcedd
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/parser@npm:7.14.1"
"@typescript-eslint/parser@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/parser@npm:7.15.0"
dependencies:
"@typescript-eslint/scope-manager": "npm:7.14.1"
"@typescript-eslint/types": "npm:7.14.1"
"@typescript-eslint/typescript-estree": "npm:7.14.1"
"@typescript-eslint/visitor-keys": "npm:7.14.1"
"@typescript-eslint/scope-manager": "npm:7.15.0"
"@typescript-eslint/types": "npm:7.15.0"
"@typescript-eslint/typescript-estree": "npm:7.15.0"
"@typescript-eslint/visitor-keys": "npm:7.15.0"
debug: "npm:^4.3.4"
peerDependencies:
eslint: ^8.56.0
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/f521462a7005cab5e4923937dcf36713d9438ded175b53332ae469d91cc9eb18cb3a23768b3c52063464280baae83f6b66db28cebb2e262d6d869d1a898b23f3
checksum: 10/0b5e7a14fa5d0680efb17e750a095729a7fb7c785d7a0fea2f9e6cbfef9e65caab2b751654b348b9ab813d222c1c3f8189ebf48561b81224d1821cee5c99d658
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/scope-manager@npm:7.14.1"
"@typescript-eslint/scope-manager@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/scope-manager@npm:7.15.0"
dependencies:
"@typescript-eslint/types": "npm:7.14.1"
"@typescript-eslint/visitor-keys": "npm:7.14.1"
checksum: 10/600a7beb96f5b96f675125285137339c2438b5b26db203a66eef52dd409e8c0db0dafb22c94547dfb963f8efdf63b0fb59e05655e2dcf84d54624863365a59e7
"@typescript-eslint/types": "npm:7.15.0"
"@typescript-eslint/visitor-keys": "npm:7.15.0"
checksum: 10/45bfdbae2d080691a34f5b37679b4a4067981baa3b82922268abdd21f6917a8dd1c4ccb12133f6c9cce81cfd640040913b223e8125235b92f42fdb57db358a3e
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/type-utils@npm:7.14.1"
"@typescript-eslint/type-utils@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/type-utils@npm:7.15.0"
dependencies:
"@typescript-eslint/typescript-estree": "npm:7.14.1"
"@typescript-eslint/utils": "npm:7.14.1"
"@typescript-eslint/typescript-estree": "npm:7.15.0"
"@typescript-eslint/utils": "npm:7.15.0"
debug: "npm:^4.3.4"
ts-api-utils: "npm:^1.3.0"
peerDependencies:
@ -4648,23 +4648,23 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/75c279948a7e7e546d692e85a0b48fc3b648ffee1773feb7ff199aba1b0847a9a16c432b133aa72d26e645627403852b7dd24829f9b3badd6d4711c4cc38e9e4
checksum: 10/64fa589b413567df3689a19ef88f3dbaed66d965e39cc548a58626eb5bd8fc4e2338496eb632f3472de9ae9800cb14d0e48ef3508efe80bdb91af8f3f1e56ad7
languageName: node
linkType: hard
"@typescript-eslint/types@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/types@npm:7.14.1"
checksum: 10/608057582bb195bd746a7bfb7c04dac4be1d4602b8fa681b2d1d50b564362b681dc2ca293b13cc4c7acc454f3a09f1ea2580415347efb7853e5df8ba34b7acdb
"@typescript-eslint/types@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/types@npm:7.15.0"
checksum: 10/b36c98344469f4bc54a5199733ea4f6d4d0f2da1070605e60d4031e2da2946b84b91a90108516c8e6e83a21030ba4e935053a0906041c920156de40683297d0b
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/typescript-estree@npm:7.14.1"
"@typescript-eslint/typescript-estree@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/typescript-estree@npm:7.15.0"
dependencies:
"@typescript-eslint/types": "npm:7.14.1"
"@typescript-eslint/visitor-keys": "npm:7.14.1"
"@typescript-eslint/types": "npm:7.15.0"
"@typescript-eslint/visitor-keys": "npm:7.15.0"
debug: "npm:^4.3.4"
globby: "npm:^11.1.0"
is-glob: "npm:^4.0.3"
@ -4674,31 +4674,31 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/f75b956f7981712d3f85498f9d9fcc2243d79d6fe71b24bc688a7c43d2a4248f73ecfb78f9d58501fde87fc44b02e26c46f9ea2ae51eb8450db79ca169f91ef9
checksum: 10/c5fb15108fbbc1bc976e827218ff7bfbc78930c5906292325ee42ba03514623e7b861497b3e3087f71ede9a757b16441286b4d234450450b0dd70ff753782736
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/utils@npm:7.14.1"
"@typescript-eslint/utils@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/utils@npm:7.15.0"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.4.0"
"@typescript-eslint/scope-manager": "npm:7.14.1"
"@typescript-eslint/types": "npm:7.14.1"
"@typescript-eslint/typescript-estree": "npm:7.14.1"
"@typescript-eslint/scope-manager": "npm:7.15.0"
"@typescript-eslint/types": "npm:7.15.0"
"@typescript-eslint/typescript-estree": "npm:7.15.0"
peerDependencies:
eslint: ^8.56.0
checksum: 10/1ef74214ca84e32f151364512a51e82b7da5590dee03d0de0e1abcf18009e569f9a0638506cf03bd4a844af634b4935458e334b7b2459e9a50a67aba7d6228c7
checksum: 10/f6de1849dee610a8110638be98ab2ec09e7cdf2f756b538b0544df2dfad86a8e66d5326a765302fe31553e8d9d3170938c0d5d38bd9c7d36e3ee0beb1bdc8172
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:7.14.1":
version: 7.14.1
resolution: "@typescript-eslint/visitor-keys@npm:7.14.1"
"@typescript-eslint/visitor-keys@npm:7.15.0":
version: 7.15.0
resolution: "@typescript-eslint/visitor-keys@npm:7.15.0"
dependencies:
"@typescript-eslint/types": "npm:7.14.1"
"@typescript-eslint/types": "npm:7.15.0"
eslint-visitor-keys: "npm:^3.4.3"
checksum: 10/42246f33cb3f9185c0b467c9a534e34a674e4fc08ba982a03aaa77dc1e569e916f1fca9ce9cd14c4df91f416e6e917bff51f98b8d8ca26ec5f67c253e8646bde
checksum: 10/0e17d7f5de767da7f98170c2efc905cdb0ceeaf04a667e12ca1a92eae64479a07f4f8e2a9b5023b055b01250916c3bcac86908cd06552610baff734fafae4464
languageName: node
linkType: hard
@ -8902,7 +8902,7 @@ __metadata:
"@codemirror/legacy-modes": "npm:6.4.0"
"@codemirror/search": "npm:6.5.6"
"@codemirror/state": "npm:6.4.1"
"@codemirror/view": "npm:6.28.2"
"@codemirror/view": "npm:6.28.3"
"@egjs/hammerjs": "npm:2.0.17"
"@formatjs/intl-datetimeformat": "npm:6.12.5"
"@formatjs/intl-displaynames": "npm:6.6.8"
@ -8924,7 +8924,7 @@ __metadata:
"@lit-labs/motion": "npm:1.0.7"
"@lit-labs/observers": "npm:2.0.2"
"@lit-labs/virtualizer": "npm:2.0.13"
"@lokalise/node-api": "npm:12.5.0"
"@lokalise/node-api": "npm:12.6.0"
"@lrnwebcomponents/simple-tooltip": "npm:8.0.2"
"@material/chips": "npm:=14.0.0-canary.53b3cad2f.0"
"@material/data-table": "npm:=14.0.0-canary.53b3cad2f.0"
@ -8986,8 +8986,8 @@ __metadata:
"@types/tar": "npm:6.1.13"
"@types/ua-parser-js": "npm:0.7.39"
"@types/webspeechapi": "npm:0.0.29"
"@typescript-eslint/eslint-plugin": "npm:7.14.1"
"@typescript-eslint/parser": "npm:7.14.1"
"@typescript-eslint/eslint-plugin": "npm:7.15.0"
"@typescript-eslint/parser": "npm:7.15.0"
"@vaadin/combo-box": "npm:24.4.0"
"@vaadin/vaadin-themable-mixin": "npm:24.4.0"
"@vibrant/color": "npm:3.2.1-alpha.1"
@ -9083,7 +9083,7 @@ __metadata:
ts-lit-plugin: "npm:2.0.2"
tsparticles-engine: "npm:2.12.0"
tsparticles-preset-links: "npm:2.12.0"
typescript: "npm:5.5.2"
typescript: "npm:5.5.3"
ua-parser-js: "npm:1.0.38"
unfetch: "npm:5.0.0"
vis-data: "npm:7.1.9"
@ -14209,13 +14209,13 @@ __metadata:
languageName: node
linkType: hard
"typescript@npm:5.5.2":
version: 5.5.2
resolution: "typescript@npm:5.5.2"
"typescript@npm:5.5.3":
version: 5.5.3
resolution: "typescript@npm:5.5.3"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10/9118b20f248e76b0dbff8737fef65dfa89d02668d4e633d2c5ceac99033a0ca5e8a1c1a53bc94da68e8f67677a88f318663dde859c9e9a09c1e116415daec2ba
checksum: 10/11a867312419ed497929aafd2f1d28b2cd41810a5eb6c6e9e169559112e9ea073d681c121a29102e67cd4478d0a4ae37a306a5800f3717f59c4337e6a9bd5e8d
languageName: node
linkType: hard
@ -14229,13 +14229,13 @@ __metadata:
languageName: node
linkType: hard
"typescript@patch:typescript@npm%3A5.5.2#optional!builtin<compat/typescript>":
version: 5.5.2
resolution: "typescript@patch:typescript@npm%3A5.5.2#optional!builtin<compat/typescript>::version=5.5.2&hash=379a07"
"typescript@patch:typescript@npm%3A5.5.3#optional!builtin<compat/typescript>":
version: 5.5.3
resolution: "typescript@patch:typescript@npm%3A5.5.3#optional!builtin<compat/typescript>::version=5.5.3&hash=379a07"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10/ac3145f65cf9e72ab29f2196e05d5816b355dc1a9195b9f010d285182a12457cfacd068be2dd22c877f88ebc966ac6e0e83f51c8586412b16499a27e3670ff4b
checksum: 10/7cf7acb78a80f749b82842f2ffe01e90e7b3e709a6f4268588e0b7599c41dca1059be217f47778fe1a380bfaf60933021ef20d002c426d4d7745e1b36c11467b
languageName: node
linkType: hard