Compare commits

..

2 Commits

Author SHA1 Message Date
Petar Petrov
45823fe4a8 css tweak 2026-04-30 14:54:11 +03:00
Petar Petrov
76568379e7 Show battery state of charge on the energy distribution card 2026-04-30 14:49:04 +03:00
28 changed files with 355 additions and 587 deletions

View File

@@ -201,7 +201,7 @@
"terser-webpack-plugin": "5.5.0",
"ts-lit-plugin": "2.0.2",
"typescript": "6.0.3",
"typescript-eslint": "8.59.1",
"typescript-eslint": "8.59.0",
"vite-tsconfig-paths": "6.1.1",
"vitest": "4.1.5",
"webpack-stats-plugin": "1.1.3",

View File

@@ -1,3 +1,17 @@
import {
mdiBattery,
mdiBattery10,
mdiBattery20,
mdiBattery30,
mdiBattery40,
mdiBattery50,
mdiBattery60,
mdiBattery70,
mdiBattery80,
mdiBattery90,
mdiBatteryAlertVariantOutline,
mdiBatteryUnknown,
} from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
const BATTERY_ICONS = {
@@ -12,6 +26,18 @@ const BATTERY_ICONS = {
90: "mdi:battery-90",
100: "mdi:battery",
};
const BATTERY_ICON_PATHS = {
10: mdiBattery10,
20: mdiBattery20,
30: mdiBattery30,
40: mdiBattery40,
50: mdiBattery50,
60: mdiBattery60,
70: mdiBattery70,
80: mdiBattery80,
90: mdiBattery90,
100: mdiBattery,
};
const BATTERY_CHARGING_ICONS = {
10: "mdi:battery-charging-10",
20: "mdi:battery-charging-20",
@@ -57,3 +83,15 @@ export const batteryLevelIcon = (
}
return BATTERY_ICONS[batteryRound];
};
export const batteryLevelIconPath = (batteryLevel: number | string): string => {
const batteryValue = Number(batteryLevel);
if (isNaN(batteryValue)) {
return mdiBatteryUnknown;
}
if (batteryValue <= 5) {
return mdiBatteryAlertVariantOutline;
}
const batteryRound = Math.round(batteryValue / 10) * 10;
return BATTERY_ICON_PATHS[batteryRound];
};

View File

@@ -1499,7 +1499,6 @@ export class HaChartBase extends LitElement {
margin-inline-start: var(--ha-space-1);
flex-shrink: 0;
white-space: nowrap;
line-height: 1;
}
.chart-legend .legend-toggle {
background: none;

View File

@@ -160,8 +160,6 @@ export class HaEntityToggle extends LitElement {
static styles = css`
:host {
display: flex;
align-items: center;
white-space: nowrap;
min-width: 38px;
}

View File

@@ -189,20 +189,6 @@ export const updateBackupConfig = (
config: BackupMutableConfig
) => hass.callWS({ type: "backup/config/update", ...config });
export const saveBackupConfig = (hass: HomeAssistant, config: BackupConfig) =>
updateBackupConfig(hass, {
create_backup: {
agent_ids: config.create_backup.agent_ids,
include_folders: config.create_backup.include_folders ?? [],
include_database: config.create_backup.include_database,
include_addons: config.create_backup.include_addons ?? [],
include_all_addons: config.create_backup.include_all_addons,
password: config.create_backup.password,
},
retention: config.retention,
schedule: config.schedule,
});
export const getBackupDownloadUrl = (
id: string,
agentId: string,

View File

@@ -164,6 +164,7 @@ export interface BatterySourceTypeEnergyPreference {
stat_energy_to: string;
stat_rate?: string; // always available if power_config is set
power_config?: PowerConfig;
stat_soc?: string;
}
export interface GasSourceTypeEnergyPreference {
type: "gas";

View File

@@ -134,7 +134,6 @@ type AutomationItem = AutomationEntity & {
formatted_state: string;
category: string | undefined;
label_entries: LabelRegistryEntry[];
labels: string[]; // search only
assistants: string[];
assistants_sortable_key: string | undefined;
};
@@ -257,9 +256,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
);
const category = entityRegEntry?.categories.automation;
const labels = labelReg && entityRegEntry?.labels;
const label_entries = (labels || [])
.map((lbl) => labelReg!.find((label) => label.label_id === lbl)!)
.filter(Boolean);
const assistants = getEntityVoiceAssistantsIds(
entityReg,
automation.entity_id
@@ -275,8 +271,9 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
category: category
? categoryReg?.find((cat) => cat.category_id === category)?.name
: undefined,
label_entries,
labels: label_entries.map((lbl) => lbl.name),
label_entries: (labels || [])
.map((lbl) => labelReg!.find((label) => label.label_id === lbl)!)
.filter(Boolean),
assistants,
assistants_sortable_key: getAssistantsSortableKey(assistants),
selectable: entityRegEntry !== undefined,

View File

@@ -1,123 +0,0 @@
import { mdiPuzzle } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../../../components/ha-card";
import "../../../../../components/ha-icon-next";
import "../../../../../components/ha-md-list";
import "../../../../../components/ha-md-list-item";
import "../../../../../components/ha-svg-icon";
import {
getSupervisorUpdateConfig,
type SupervisorUpdateConfig,
} from "../../../../../data/supervisor/update";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types";
@customElement("ha-backup-overview-app-update-backup")
class HaBackupOverviewAppUpdateBackup extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _supervisorUpdateConfig?: SupervisorUpdateConfig;
protected firstUpdated() {
this._fetchSupervisorUpdateConfig();
}
public connectedCallback() {
super.connectedCallback();
if (this.hasUpdated) {
this._fetchSupervisorUpdateConfig();
}
}
private async _fetchSupervisorUpdateConfig() {
try {
this._supervisorUpdateConfig = await getSupervisorUpdateConfig(this.hass);
} catch (err) {
// eslint-disable-next-line no-console
console.error(err);
}
}
private _appUpdateBackupDescription() {
if (!this._supervisorUpdateConfig) {
return this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.local_only"
);
}
if (!this._supervisorUpdateConfig.add_on_backup_before_update) {
return this.hass.localize(
"ui.panel.config.backup.schedule.update_preference.skip_backups"
);
}
const copies =
this._supervisorUpdateConfig.add_on_backup_retain_copies || 1;
return `${this.hass.localize(
"ui.panel.config.backup.schedule.update_preference.backup_before_update"
)} ${this.hass.localize(
"ui.panel.config.backup.overview.settings.schedule_copies_backups",
{ count: copies }
)}`;
}
protected render() {
return html`
<ha-card>
<div class="card-header">
${this.hass.localize(
"ui.panel.config.backup.overview.app_update_backup.title"
)}
</div>
<div class="card-content">
<ha-md-list>
<ha-md-list-item
type="link"
href="/config/backup/app-update-backups"
>
<ha-svg-icon slot="start" .path=${mdiPuzzle}></ha-svg-icon>
<div slot="headline">${this._appUpdateBackupDescription()}</div>
<div slot="supporting-text">
${this.hass.localize(
"ui.panel.config.backup.overview.app_update_backup.description"
)}
</div>
<ha-icon-next slot="end"></ha-icon-next>
</ha-md-list-item>
</ha-md-list>
</div>
</ha-card>
`;
}
static get styles(): CSSResultGroup {
return [
haStyle,
css`
.card-header {
padding-bottom: 8px;
}
.card-content {
padding-left: 0;
padding-right: 0;
padding-top: 0;
}
ha-md-list {
padding-top: 0;
padding-bottom: 0;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-backup-overview-app-update-backup": HaBackupOverviewAppUpdateBackup;
}
}

View File

@@ -1,154 +0,0 @@
import { css, html, LitElement, nothing } from "lit";
import type { PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-alert";
import "../../../components/ha-card";
import {
getSupervisorUpdateConfig,
updateSupervisorUpdateConfig,
type SupervisorUpdateConfig,
} from "../../../data/supervisor/update";
import "../../../layouts/hass-subpage";
import type { HomeAssistant } from "../../../types";
import "./components/config/ha-backup-config-addon";
@customElement("ha-config-backup-app-update-backups")
class HaConfigBackupAppUpdateBackups extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public narrow = false;
@state() private _supervisorUpdateConfig?: SupervisorUpdateConfig;
@state() private _error?: string;
protected willUpdate(changedProps: PropertyValues<this>): void {
super.willUpdate(changedProps);
if (
!this.hasUpdated &&
this.hass &&
isComponentLoaded(this.hass.config, "hassio")
) {
this._getSupervisorUpdateConfig();
}
}
protected render() {
return html`
<hass-subpage
back-path="/config/backup/overview"
.hass=${this.hass}
.narrow=${this.narrow}
.header=${this.hass.localize(
"ui.panel.config.backup.app_update_backups.header"
)}
>
<div class="content">
<ha-card>
<div class="card-content">
<p>
${this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.description"
)}
</p>
<p>
${this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.local_only"
)}
</p>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: nothing}
<ha-backup-config-addon
.hass=${this.hass}
.supervisorUpdateConfig=${this._supervisorUpdateConfig}
@update-config-changed=${this._supervisorUpdateConfigChanged}
></ha-backup-config-addon>
</div>
</ha-card>
</div>
</hass-subpage>
`;
}
private async _getSupervisorUpdateConfig() {
try {
this._supervisorUpdateConfig = await getSupervisorUpdateConfig(this.hass);
this._error = undefined;
} catch (err: any) {
// eslint-disable-next-line no-console
console.error(err);
this._error = this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.error_load",
{
error: err?.message || err,
}
);
}
}
private async _supervisorUpdateConfigChanged(ev) {
const config = ev.detail.value as SupervisorUpdateConfig;
this._supervisorUpdateConfig = {
...this._supervisorUpdateConfig,
...config,
} as SupervisorUpdateConfig;
this._debounceSaveSupervisorUpdateConfig();
}
private _debounceSaveSupervisorUpdateConfig = debounce(
() => this._saveSupervisorUpdateConfig(),
500
);
private async _saveSupervisorUpdateConfig() {
if (!this._supervisorUpdateConfig) {
return;
}
try {
await updateSupervisorUpdateConfig(
this.hass,
this._supervisorUpdateConfig
);
this._error = undefined;
} catch (err: any) {
// eslint-disable-next-line no-console
console.error(err);
this._error = this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.error_save",
{
error: err?.message || err?.toString(),
}
);
}
}
static styles = css`
p {
color: var(--secondary-text-color);
}
.content {
padding: 28px 20px 0;
max-width: 690px;
margin: 0 auto;
gap: var(--ha-space-6);
display: flex;
flex-direction: column;
margin-bottom: 24px;
}
.card-content {
padding-bottom: 0;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-config-backup-app-update-backups": HaConfigBackupAppUpdateBackups;
}
}

View File

@@ -1,9 +1,8 @@
import { mdiDotsVertical, mdiPlus, mdiUpload } from "@mdi/js";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-button";
import "../../../components/ha-card";
import "../../../components/ha-dropdown";
@@ -24,7 +23,6 @@ import {
computeBackupAgentName,
generateBackup,
generateBackupWithAutomaticSettings,
saveBackupConfig,
} from "../../../data/backup";
import type { ManagerStateEvent } from "../../../data/backup_manager";
import type { CloudStatus } from "../../../data/cloud";
@@ -34,12 +32,10 @@ import { haStyle } from "../../../resources/styles";
import type { HomeAssistant, Route } from "../../../types";
import { showAlertDialog } from "../../lovelace/custom-card-helpers";
import "./components/overview/ha-backup-overview-backups";
import "./components/overview/ha-backup-overview-app-update-backup";
import "./components/overview/ha-backup-overview-onboarding";
import "./components/overview/ha-backup-overview-progress";
import "./components/overview/ha-backup-overview-settings";
import "./components/overview/ha-backup-overview-summary";
import "./components/config/ha-backup-config-encryption-key";
import { showBackupOnboardingDialog } from "./dialogs/show-dialog-backup_onboarding";
import { showGenerateBackupDialog } from "./dialogs/show-dialog-generate-backup";
import { showNewBackupDialog } from "./dialogs/show-dialog-new-backup";
@@ -72,54 +68,10 @@ class HaConfigBackupOverview extends LitElement {
{ uploaded_bytes: number; total_bytes: number }
> = {};
@state() private _config?: BackupConfig;
protected willUpdate(changedProperties: PropertyValues<this>): void {
super.willUpdate(changedProperties);
if (changedProperties.has("config") && !this._config) {
this._config = this.config;
}
}
public connectedCallback(): void {
super.connectedCallback();
// Update config when the page is displayed (e.g. when coming back from a settings page)
this._config = this.config;
}
private _uploadBackup = async () => {
await showUploadBackupDialog(this, {});
};
private _encryptionKeyChanged(ev) {
if (!this._config) {
return;
}
const password = ev.detail.value as string;
this._config = {
...this._config,
create_backup: {
...this._config.create_backup,
password,
},
};
this._debounceSaveConfig();
}
private _debounceSaveConfig = debounce(() => this._saveConfig(), 500);
private async _saveConfig() {
if (!this._config) {
return;
}
await saveBackupConfig(this.hass, this._config);
fireEvent(this, "ha-refresh-backup-config");
}
private _handleOnboardingButtonClick(ev) {
ev.stopPropagation();
this._setupAutomaticBackup(true);
@@ -282,41 +234,13 @@ class HaConfigBackupOverview extends LitElement {
.backups=${this.backups}
></ha-backup-overview-backups>
${!this._needsOnboarding && this._config
${!this._needsOnboarding && this.config
? html`
<ha-card>
<div class="card-header">
${this.hass.localize(
"ui.panel.config.backup.settings.encryption_key.title"
)}
</div>
<div class="card-content">
<p>
${this.hass.localize(
"ui.panel.config.backup.settings.encryption_key.description"
)}
</p>
<ha-backup-config-encryption-key
.hass=${this.hass}
.value=${this._config.create_backup.password}
@value-changed=${this._encryptionKeyChanged}
></ha-backup-config-encryption-key>
</div>
</ha-card>
<ha-backup-overview-settings
.hass=${this.hass}
.config=${this._config}
.config=${this.config!}
.agents=${this.agents}
></ha-backup-overview-settings>
${this.hass.config.components.includes("hassio")
? html`
<ha-backup-overview-app-update-backup
.hass=${this.hass}
></ha-backup-overview-app-update-backup>
`
: nothing}
`
: nothing}
</div>
@@ -346,10 +270,6 @@ class HaConfigBackupOverview extends LitElement {
return [
haStyle,
css`
p {
color: var(--secondary-text-color);
}
.content {
padding: 28px 20px 0;
max-width: 690px;
@@ -363,6 +283,10 @@ class HaConfigBackupOverview extends LitElement {
display: flex;
justify-content: flex-end;
}
.card-content {
padding-left: 0;
padding-right: 0;
}
.loading {
display: flex;
}

View File

@@ -16,7 +16,7 @@ import "../../../components/ha-icon-button";
import "../../../components/ha-icon-next";
import "../../../components/ha-svg-icon";
import type { BackupAgent, BackupConfig } from "../../../data/backup";
import { saveBackupConfig } from "../../../data/backup";
import { updateBackupConfig } from "../../../data/backup";
import type { CloudStatus } from "../../../data/cloud";
import {
getSupervisorUpdateConfig,
@@ -27,9 +27,11 @@ import "../../../layouts/hass-subpage";
import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
import { documentationUrl } from "../../../util/documentation-url";
import "./components/config/ha-backup-config-addon";
import "./components/config/ha-backup-config-agents";
import "./components/config/ha-backup-config-data";
import type { BackupConfigData } from "./components/config/ha-backup-config-data";
import "./components/config/ha-backup-config-encryption-key";
import "./components/config/ha-backup-config-schedule";
import type { BackupConfigSchedule } from "./components/config/ha-backup-config-schedule";
import { showLocalBackupLocationDialog } from "./dialogs/show-dialog-local-backup-location";
@@ -77,7 +79,7 @@ class HaConfigBackupSettings extends LitElement {
// eslint-disable-next-line no-console
console.error(err);
this._supervisorUpdateConfigError = this.hass.localize(
"ui.panel.config.backup.settings.schedule.error_load",
"ui.panel.config.backup.settings.app_update_backup.error_load",
{
error: err?.message || err,
}
@@ -313,6 +315,57 @@ class HaConfigBackupSettings extends LitElement {
: nothing}
</div>
</ha-card>
${supervisor
? html`<ha-card>
<div class="card-header">
${this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.title"
)}
</div>
<div class="card-content">
<p>
${this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.description"
)}
</p>
<p>
${this.hass.localize(
"ui.panel.config.backup.settings.app_update_backup.local_only"
)}
</p>
${this._supervisorUpdateConfigError
? html`<ha-alert alert-type="error">
${this._supervisorUpdateConfigError}
</ha-alert>`
: nothing}
<ha-backup-config-addon
.hass=${this.hass}
.supervisorUpdateConfig=${this._supervisorUpdateConfig}
@update-config-changed=${this
._supervisorUpdateConfigChanged}
></ha-backup-config-addon>
</div>
</ha-card>`
: nothing}
<ha-card>
<div class="card-header">
${this.hass.localize(
"ui.panel.config.backup.settings.encryption_key.title"
)}
</div>
<div class="card-content">
<p>
${this.hass.localize(
"ui.panel.config.backup.settings.encryption_key.description"
)}
</p>
<ha-backup-config-encryption-key
.hass=${this.hass}
.value=${this._config.create_backup.password}
@value-changed=${this._encryptionKeyChanged}
></ha-backup-config-encryption-key>
</div>
</ha-card>
</div>
</hass-subpage>
`;
@@ -385,6 +438,18 @@ class HaConfigBackupSettings extends LitElement {
this._debounceSave();
}
private _encryptionKeyChanged(ev) {
const password = ev.detail.value as string;
this._config = {
...this._config!,
create_backup: {
...this._config!.create_backup,
password: password,
},
};
this._debounceSave();
}
private _debounceSaveSupervisorUpdateConfig = debounce(
() => this._saveSupervisorUpdateConfig(),
500
@@ -403,7 +468,7 @@ class HaConfigBackupSettings extends LitElement {
// eslint-disable-next-line no-console
console.error(err);
this._supervisorUpdateConfigError = this.hass.localize(
"ui.panel.config.backup.settings.schedule.error_save",
"ui.panel.config.backup.settings.app_update_backup.error_save",
{
error: err?.message || err?.toString(),
}
@@ -414,7 +479,18 @@ class HaConfigBackupSettings extends LitElement {
private _debounceSave = debounce(() => this._save(), 500);
private async _save() {
await saveBackupConfig(this.hass, this._config!);
await updateBackupConfig(this.hass, {
create_backup: {
agent_ids: this._config!.create_backup.agent_ids,
include_folders: this._config!.create_backup.include_folders ?? [],
include_database: this._config!.create_backup.include_database,
include_addons: this._config!.create_backup.include_addons ?? [],
include_all_addons: this._config!.create_backup.include_all_addons,
password: this._config!.create_backup.password,
},
retention: this._config!.retention,
schedule: this._config!.schedule,
});
fireEvent(this, "ha-refresh-backup-config");
}

View File

@@ -125,11 +125,6 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) {
load: () => import("./ha-config-backup-settings"),
cache: true,
},
"app-update-backups": {
tag: "ha-config-backup-app-update-backups",
load: () => import("./ha-config-backup-app-update-backups"),
cache: true,
},
location: {
tag: "ha-config-backup-location",
load: () => import("./ha-config-backup-location"),

View File

@@ -244,13 +244,9 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
max-width: 1040px;
margin: 0 auto;
}
.card-content {
display: flex;
flex-direction: column;
gap: var(--ha-space-4);
}
.description {
margin: 0;
margin-bottom: var(--ha-space-4);
}
ha-textarea {
width: 100%;

View File

@@ -29,6 +29,8 @@ import {
import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
const energyUnitClasses = ["energy"];
const socStatisticsUnits = ["%"];
const socDeviceClass = "battery";
@customElement("dialog-energy-battery-settings")
export class DialogEnergyBatterySettings
@@ -180,6 +182,21 @@ export class DialogEnergyBatterySettings
@power-config-changed=${this._handlePowerConfigChanged}
></ha-energy-power-config>
<ha-statistic-picker
.hass=${this.hass}
.helpMissingEntityUrl=${energyStatisticHelpUrl}
.value=${this._source.stat_soc}
.includeStatisticsUnitOfMeasurement=${socStatisticsUnits}
.includeDeviceClass=${socDeviceClass}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.state_of_charge"
)}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.state_of_charge_helper"
)}
@value-changed=${this._statisticSocChanged}
></ha-statistic-picker>
<ha-dialog-footer slot="footer">
<ha-button
appearance="plain"
@@ -232,6 +249,13 @@ export class DialogEnergyBatterySettings
this._powerConfig = ev.detail.powerConfig;
}
private _statisticSocChanged(ev: ValueChangedEvent<string>) {
this._source = {
...this._source!,
stat_soc: ev.detail.value || undefined,
};
}
private async _save() {
try {
const source: BatterySourceTypeEnergyPreference = {
@@ -245,6 +269,10 @@ export class DialogEnergyBatterySettings
source.power_config = { ...this._powerConfig };
}
if (this._source!.stat_soc) {
source.stat_soc = this._source!.stat_soc;
}
await this._params!.saveCallback(source);
this.closeDialog();
} catch (err: any) {
@@ -257,7 +285,8 @@ export class DialogEnergyBatterySettings
haStyle,
haStyleDialog,
css`
ha-statistic-picker {
ha-statistic-picker,
ha-energy-power-config {
display: block;
margin-bottom: var(--ha-space-4);
}

View File

@@ -146,7 +146,6 @@ interface HelperItem {
category: string | undefined;
area?: string;
label_entries: LabelRegistryEntry[];
labels: string[]; // search only
assistants: string[];
assistants_sortable_key: string | undefined;
disabled?: boolean;
@@ -553,9 +552,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
const entityRegEntry =
entityRegistryByEntityId(entityReg)[item.entity_id];
const labels = labelReg && entityRegEntry?.labels;
const label_entries = (labels || []).map(
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
);
const category = entityRegEntry?.categories.helpers;
const deviceId = entityRegEntry?.device_id;
const areaId =
@@ -576,8 +572,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
`ui.panel.config.helpers.types.${item.type}` as LocalizeKeys
) ||
item.type,
label_entries,
labels: label_entries.map((lbl) => lbl.name),
label_entries: (labels || []).map(
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
),
category: category
? categoryReg?.find((cat) => cat.category_id === category)?.name
: undefined,

View File

@@ -122,7 +122,6 @@ type SceneItem = SceneEntity & {
area: string | undefined;
category: string | undefined;
label_entries: LabelRegistryEntry[];
labels: string[]; // search only
assistants: string[];
assistants_sortable_key: string | undefined;
editable: boolean;
@@ -240,9 +239,6 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
);
const category = entityRegEntry?.categories.scene;
const labels = labelReg && entityRegEntry?.labels;
const label_entries = (labels || []).map(
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
);
const assistants = getEntityVoiceAssistantsIds(
entityReg,
scene.entity_id
@@ -256,8 +252,9 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
category: category
? categoryReg?.find((cat) => cat.category_id === category)?.name
: undefined,
label_entries,
labels: label_entries.map((lbl) => lbl.name),
label_entries: (labels || []).map(
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
),
assistants,
assistants_sortable_key: getAssistantsSortableKey(assistants),
selectable: entityRegEntry !== undefined,

View File

@@ -127,7 +127,6 @@ type ScriptItem = ScriptEntity & {
last_triggered: string | undefined;
category: string | undefined;
label_entries: LabelRegistryEntry[];
labels: string[]; // search only
assistants: string[];
assistants_sortable_key: string | undefined;
};
@@ -246,9 +245,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
);
const category = entityRegEntry?.categories.script;
const labels = labelReg && entityRegEntry?.labels;
const label_entries = (labels || []).map(
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
);
const assistants = getEntityVoiceAssistantsIds(
entityReg,
script.entity_id
@@ -263,8 +259,9 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
category: category
? categoryReg?.find((cat) => cat.category_id === category)?.name
: undefined,
label_entries,
labels: label_entries.map((lbl) => lbl.name),
label_entries: (labels || []).map(
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
),
assistants,
assistants_sortable_key: getAssistantsSortableKey(assistants),
selectable: entityRegEntry !== undefined,

View File

@@ -16,6 +16,7 @@ import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing, svg } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { batteryLevelIconPath } from "../../../../common/entity/battery_icon";
import "../../../../components/ha-button";
import "../../../../components/ha-card";
import "../../../../components/ha-svg-icon";
@@ -100,14 +101,34 @@ class HuiEnergyDistrubutionCard
}
protected shouldUpdate(changedProps: PropertyValues): boolean {
return (
if (
hasConfigChanged(this, changedProps) ||
changedProps.size > 1 ||
!changedProps.has("hass") ||
(!!this._data?.co2SignalEntity &&
this.hass.states[this._data.co2SignalEntity] !==
changedProps.get("hass").states[this._data.co2SignalEntity])
);
!changedProps.has("hass")
) {
return true;
}
const oldStates = changedProps.get("hass").states;
if (
this._data?.co2SignalEntity &&
this.hass.states[this._data.co2SignalEntity] !==
oldStates[this._data.co2SignalEntity]
) {
return true;
}
const batteries = this._data
? energySourcesByType(this._data.prefs).battery
: undefined;
if (
batteries?.some(
(source) =>
source.stat_soc &&
this.hass.states[source.stat_soc] !== oldStates[source.stat_soc]
)
) {
return true;
}
return false;
}
protected willUpdate() {
@@ -174,10 +195,24 @@ class HuiEnergyDistrubutionCard
let totalBatteryIn: number | null = null;
let totalBatteryOut: number | null = null;
let batteryIconPath = mdiBatteryHigh;
if (hasBattery) {
totalBatteryIn = summedData.total.to_battery ?? 0;
totalBatteryOut = summedData.total.from_battery ?? 0;
const socValues = types
.battery!.map((source) =>
source.stat_soc
? Number(this.hass.states[source.stat_soc]?.state)
: NaN
)
.filter((value) => Number.isFinite(value));
if (socValues.length) {
const averageSoc =
socValues.reduce((sum, value) => sum + value, 0) / socValues.length;
batteryIconPath = batteryLevelIconPath(averageSoc);
}
}
let returnedToGrid: number | null = null;
@@ -569,7 +604,7 @@ class HuiEnergyDistrubutionCard
${hasBattery
? html` <div class="circle-container battery">
<div class="circle">
<ha-svg-icon .path=${mdiBatteryHigh}></ha-svg-icon>
<ha-svg-icon .path=${batteryIconPath}></ha-svg-icon>
<span class="battery-in">
<ha-svg-icon
class="small"

View File

@@ -35,10 +35,7 @@ import {
HOME_SUMMARIES_ICONS,
type HomeSummary,
} from "../strategies/home/helpers/home-summaries";
import {
filterLowBatteryEntities,
filterUnavailableBatteryEntities,
} from "../../maintenance/strategies/maintenance-view-strategy";
import { filterNeedsAttentionEntities } from "../../maintenance/strategies/maintenance-view-strategy";
import type { LovelaceCard, LovelaceGridOptions } from "../types";
import { tileCardStyle } from "./tile/tile-card-style";
import type { HomeSummaryCard } from "./types";
@@ -261,48 +258,19 @@ export class HuiHomeSummaryCard
maintenanceFilters
);
const lowBatteryEntities = filterLowBatteryEntities(
const needsAttentionEntities = filterNeedsAttentionEntities(
this.hass!,
maintenanceEntities
);
const unavailableBatteryEntities = filterUnavailableBatteryEntities(
this.hass!,
maintenanceEntities
);
const lowBatteryText =
lowBatteryEntities.length > 0
? this.hass.localize(
"ui.card.home-summary.count_maintenance_low_battery_issues",
{
count: lowBatteryEntities.length,
}
)
: undefined;
const unavailableText =
unavailableBatteryEntities.length > 0
? this.hass.localize(
"ui.card.home-summary.count_maintenance_issues_unavailable_battery_entities",
{
count: unavailableBatteryEntities.length,
}
)
: undefined;
if (lowBatteryText && unavailableText) {
return `${lowBatteryText}, ${unavailableText}`;
if (needsAttentionEntities.length > 0) {
return this.hass.localize(
"ui.card.home-summary.count_maintenance_issues",
{
count: needsAttentionEntities.length,
}
);
}
if (lowBatteryText) {
return lowBatteryText;
}
if (unavailableText) {
return unavailableText;
}
return this.hass.localize("ui.card.home-summary.all_maintenance_good");
}
case "energy": {

View File

@@ -12,7 +12,7 @@ import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { handleAction } from "../common/handle-action";
import { hasAction, hasAnyAction } from "../common/has-action";
import { hasAction } from "../common/has-action";
import { hasConfigChanged } from "../common/has-changed";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
@@ -52,17 +52,10 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
throw new Error("Image required");
}
if (config.image_entity) {
this._config = {
tap_action: { action: "more-info" },
...config,
};
} else {
this._config = {
tap_action: { action: "none" },
...config,
};
}
this._config = {
tap_action: { action: "more-info" },
...config,
};
}
protected shouldUpdate(changedProps: PropertyValues): boolean {
@@ -174,11 +167,6 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
return nothing;
}
const clickable = Boolean(
(this._config.image_entity && !this._config.tap_action) ||
hasAnyAction(this._config)
);
return html`
<ha-card
@action=${this._handleAction}
@@ -192,7 +180,15 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
: undefined
)}
class=${classMap({
clickable,
clickable: Boolean(
(this._config.image_entity && !this._config.tap_action) ||
(this._config.tap_action &&
this._config.tap_action.action !== "none") ||
(this._config.hold_action &&
this._config.hold_action.action !== "none") ||
(this._config.double_tap_action &&
this._config.double_tap_action.action !== "none")
),
})}
>
<img

View File

@@ -419,7 +419,6 @@ export class HuiDialogEditBadge
.content {
width: 100%;
max-width: 100%;
gap: var(--ha-space-3);
}
}

View File

@@ -419,7 +419,6 @@ export class HuiDialogEditCard
.content {
width: 100%;
max-width: 100%;
gap: var(--ha-space-3);
}
}

View File

@@ -68,7 +68,9 @@ export class HuiPictureCardEditor
{
name: "tap_action",
selector: {
ui_action: {},
ui_action: {
default_action: "more-info",
},
},
context: ACTION_RELATED_CONTEXT,
},

View File

@@ -8,7 +8,7 @@ import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { handleAction } from "../common/handle-action";
import { hasAction, hasAnyAction } from "../common/has-action";
import { hasAction } from "../common/has-action";
import type { LovelaceHeaderFooter } from "../types";
import type { PictureHeaderFooterConfig } from "./types";
@@ -56,7 +56,9 @@ export class HuiPictureHeaderFooter
return nothing;
}
const clickable = hasAnyAction(this._config);
const clickable = Boolean(
this._config.tap_action || this._config.hold_action
);
return html`
<img

View File

@@ -31,7 +31,7 @@ export const maintenanceEntityFilters: EntityFilter[] = [
const LOW_BATTERY_THRESHOLD = 20;
export const filterLowBatteryEntities = (
export const filterNeedsAttentionEntities = (
hass: HomeAssistant,
entityIds: string[]
): string[] =>
@@ -40,14 +40,6 @@ export const filterLowBatteryEntities = (
return !isNaN(stateValue) && stateValue <= LOW_BATTERY_THRESHOLD;
});
export const filterUnavailableBatteryEntities = (
hass: HomeAssistant,
entityIds: string[]
): string[] =>
entityIds.filter((entityId) => {
return hass.states[entityId]?.state === "unavailable";
});
const computeBatteryTileCard = (entityId: string): TileCardConfig => ({
type: "tile",
entity: entityId,

View File

@@ -218,8 +218,7 @@
"all_secure": "All secure",
"no_media_playing": "No media playing",
"count_media_playing": "{count} {count, plural,\n one {playing}\n other {playing}\n}",
"count_maintenance_low_battery_issues": "{count} {count, plural,\n one {low battery}\n other {low batteries}\n}",
"count_maintenance_issues_unavailable_battery_entities": "{count} {count, plural,\n one {unavailable device}\n other {unavailable devices}\n}",
"count_maintenance_issues": "{count} {count, plural,\n one {issue}\n other {issues}\n}",
"all_maintenance_good": "All good",
"count_persons_home": "{count} {count, plural,\n one {person}\n other {people}\n} home",
"nobody_home": "No one home"
@@ -3567,7 +3566,7 @@
"show_all": "Show all backups"
},
"settings": {
"title": "Automatic backup",
"title": "Backup settings",
"configure": "Configure backup settings",
"schedule": "Automatic backup schedule and retention",
"schedule_copies_all": "and keep all backups",
@@ -3613,10 +3612,6 @@
"sat": "Sa",
"sun": "Su"
}
},
"app_update_backup": {
"title": "App update backup",
"description": "Backup behavior for app updates"
}
},
"backups": {
@@ -3628,15 +3623,13 @@
"new_backup": "[%key:ui::panel::config::backup::overview::new_backup%]"
},
"settings": {
"header": "Automatic backups",
"header": "Backup settings",
"menu": {
"change_default_location": "Change default action location"
},
"schedule": {
"title": "Backup cycle",
"description": "Let Home Assistant take care of your backups by creating a scheduled backup that also removes older backups.",
"error_load": "Error loading Supervisor update config: {error}",
"error_save": "Error saving Supervisor update config: {error}"
"title": "Automatic backups",
"description": "Let Home Assistant take care of your backups by creating a scheduled backup that also removes older backups."
},
"data": {
"title": "Backup data"
@@ -3664,9 +3657,6 @@
"error_save": "Error saving Supervisor update config: {error}"
}
},
"app_update_backups": {
"header": "App update backups"
},
"details": {
"header": "Backup",
"not_found": "Not found",
@@ -4171,6 +4161,8 @@
"energy_helper_out": "Pick a sensor that measures the electricity flowing out of the battery in either of {unit}.",
"energy_into_battery": "Energy charged into the battery",
"energy_out_of_battery": "Energy discharged from the battery",
"state_of_charge": "Battery state of charge sensor",
"state_of_charge_helper": "Sensor reporting battery state of charge as %.",
"power": "Battery power",
"power_helper": "Pick a sensor which measures the electricity flowing into and out of the battery in either of {unit}. Positive values indicate discharging the battery, negative values indicate charging the battery.",
"sensor_type": "Type of power measurement",

View File

@@ -1,8 +1,17 @@
import {
mdiBattery,
mdiBattery10,
mdiBattery50,
mdiBattery90,
mdiBatteryAlertVariantOutline,
mdiBatteryUnknown,
} from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import { describe, it, expect } from "vitest";
import { describe, expect, it } from "vitest";
import {
batteryIcon,
batteryLevelIcon,
batteryLevelIconPath,
} from "../../../src/common/entity/battery_icon";
describe("batteryIcon", () => {
@@ -43,3 +52,24 @@ describe("batteryLevelIcon", () => {
expect(batteryLevelIcon("on")).toBe("mdi:battery-alert");
});
});
describe("batteryLevelIconPath", () => {
it("rounds to the nearest 10% bucket", () => {
expect(batteryLevelIconPath(46)).toBe(mdiBattery50);
expect(batteryLevelIconPath(94)).toBe(mdiBattery90);
expect(batteryLevelIconPath(95)).toBe(mdiBattery);
});
it("returns the alert path for very low levels", () => {
expect(batteryLevelIconPath(0)).toBe(mdiBatteryAlertVariantOutline);
expect(batteryLevelIconPath(5)).toBe(mdiBatteryAlertVariantOutline);
});
it("returns the 10% bucket just above the alert threshold", () => {
expect(batteryLevelIconPath(6)).toBe(mdiBattery10);
});
it("returns the unknown path for non-numeric input", () => {
expect(batteryLevelIconPath("unavailable")).toBe(mdiBatteryUnknown);
});
});

146
yarn.lock
View File

@@ -4383,105 +4383,105 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/eslint-plugin@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/eslint-plugin@npm:8.59.1"
"@typescript-eslint/eslint-plugin@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/eslint-plugin@npm:8.59.0"
dependencies:
"@eslint-community/regexpp": "npm:^4.12.2"
"@typescript-eslint/scope-manager": "npm:8.59.1"
"@typescript-eslint/type-utils": "npm:8.59.1"
"@typescript-eslint/utils": "npm:8.59.1"
"@typescript-eslint/visitor-keys": "npm:8.59.1"
"@typescript-eslint/scope-manager": "npm:8.59.0"
"@typescript-eslint/type-utils": "npm:8.59.0"
"@typescript-eslint/utils": "npm:8.59.0"
"@typescript-eslint/visitor-keys": "npm:8.59.0"
ignore: "npm:^7.0.5"
natural-compare: "npm:^1.4.0"
ts-api-utils: "npm:^2.5.0"
peerDependencies:
"@typescript-eslint/parser": ^8.59.1
"@typescript-eslint/parser": ^8.59.0
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: ">=4.8.4 <6.1.0"
checksum: 10/c736ee32211a3751e31151b51dacc8cfa5bf18e086f2a87aba7ee325f7e2fa96d8b9febdbaf4dfa70d14954312b7b9740fbe5d5886b3f8561c4a94a9c7ff7688
checksum: 10/fcf2c85cb37d61854d2c03fa11c66ad58d99f4eee731dd09663f20f0395e642b12edeab2a6c368ac1806505b2071a01de01bc30b9011fa309299836e868a293a
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/parser@npm:8.59.1"
"@typescript-eslint/parser@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/parser@npm:8.59.0"
dependencies:
"@typescript-eslint/scope-manager": "npm:8.59.1"
"@typescript-eslint/types": "npm:8.59.1"
"@typescript-eslint/typescript-estree": "npm:8.59.1"
"@typescript-eslint/visitor-keys": "npm:8.59.1"
"@typescript-eslint/scope-manager": "npm:8.59.0"
"@typescript-eslint/types": "npm:8.59.0"
"@typescript-eslint/typescript-estree": "npm:8.59.0"
"@typescript-eslint/visitor-keys": "npm:8.59.0"
debug: "npm:^4.4.3"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: ">=4.8.4 <6.1.0"
checksum: 10/b014b485e5ec9c7430a87117271836b86fd80083fe6b1d216167313518f26222f45c0ee3f4cbc0616dbd6335cbde50336d8953ca5ffefecc55b2d896ac7645f9
checksum: 10/b8990e1b67e6f55aa4884807e6c3b6bd08c58f96ea4f03f19e7aba3fc1b16f040fe58378490de9bd831c804eb48e633e30e5baf291b8e8dd53960424e5751391
languageName: node
linkType: hard
"@typescript-eslint/project-service@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/project-service@npm:8.59.1"
"@typescript-eslint/project-service@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/project-service@npm:8.59.0"
dependencies:
"@typescript-eslint/tsconfig-utils": "npm:^8.59.1"
"@typescript-eslint/types": "npm:^8.59.1"
"@typescript-eslint/tsconfig-utils": "npm:^8.59.0"
"@typescript-eslint/types": "npm:^8.59.0"
debug: "npm:^4.4.3"
peerDependencies:
typescript: ">=4.8.4 <6.1.0"
checksum: 10/dd98f49a407cb21999d31ec527a0f8c2c34422dde9fdb21210d66c3cc3d498d9d3678d95c99d76450af68ce3392692902d9ba044718d6c99122655df7afdc0a7
checksum: 10/b842f1e0623c3a679d21d76c7ca38698787681d40f6a9ce93c8983120fb6795a2395907d530e4f8d89b4ac5bc65e71bbfdf2d8060f210c8487cffdae40baea74
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/scope-manager@npm:8.59.1"
"@typescript-eslint/scope-manager@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/scope-manager@npm:8.59.0"
dependencies:
"@typescript-eslint/types": "npm:8.59.1"
"@typescript-eslint/visitor-keys": "npm:8.59.1"
checksum: 10/50c941d1af470d3e67a9bd2247c541a676ae6bb2931440a44458682d61382ba1194ce29d0388dd1e538c5a35d7a542febd9519d8170abe758692d1b6cd196eab
"@typescript-eslint/types": "npm:8.59.0"
"@typescript-eslint/visitor-keys": "npm:8.59.0"
checksum: 10/8bb1182559e7676120ba12bdac11edea9fb414bd33d379a1902b035b8b4b68d23ad239d845bfe6943b5da13ecd938ea1482c73e8c6ddb4d7e3e0f8e111467e28
languageName: node
linkType: hard
"@typescript-eslint/tsconfig-utils@npm:8.59.1, @typescript-eslint/tsconfig-utils@npm:^8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/tsconfig-utils@npm:8.59.1"
"@typescript-eslint/tsconfig-utils@npm:8.59.0, @typescript-eslint/tsconfig-utils@npm:^8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/tsconfig-utils@npm:8.59.0"
peerDependencies:
typescript: ">=4.8.4 <6.1.0"
checksum: 10/9e3351bb182bb02f6f140759472f08ce334c7c96f4ebfeec8e9e404fe60b8fe1865e1a6d1b50526f83f41e7224301485e46459df6c3675923f3b657177415cd7
checksum: 10/9c094c199be4803d696dbf7cb5cdb76741876e412bf97ddde0133a75e11bc47345354b3bb188a0ff101b7ce2c582187e758696ab89c1981892a43162f36d0af1
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/type-utils@npm:8.59.1"
"@typescript-eslint/type-utils@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/type-utils@npm:8.59.0"
dependencies:
"@typescript-eslint/types": "npm:8.59.1"
"@typescript-eslint/typescript-estree": "npm:8.59.1"
"@typescript-eslint/utils": "npm:8.59.1"
"@typescript-eslint/types": "npm:8.59.0"
"@typescript-eslint/typescript-estree": "npm:8.59.0"
"@typescript-eslint/utils": "npm:8.59.0"
debug: "npm:^4.4.3"
ts-api-utils: "npm:^2.5.0"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: ">=4.8.4 <6.1.0"
checksum: 10/8a8a71656f8fab446024e55b24f6f6c4b3ee4d4cdcb593ff68ec0ca10530fcb4d451628c03898c929e91445a999cbe980c0cfaec1b53a7c5ddc8ac899ad665fa
checksum: 10/9c2d34c10676d5726f93b975136295971ac7d2a53f74bfba51ae71deefaa36292adda79d016782196b729429143634b7f90224c27dcdb3a884b9771128be7490
languageName: node
linkType: hard
"@typescript-eslint/types@npm:8.59.1, @typescript-eslint/types@npm:^8.56.0, @typescript-eslint/types@npm:^8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/types@npm:8.59.1"
checksum: 10/4d324a01c2314d8e196b43b9dc5fe9a4d82c1b65f4915cd2f965879c5565d4453603b6f7b6bcdc436fb629135f07ad0f9d274e4697b02ce8bc1c0310916f7ace
"@typescript-eslint/types@npm:8.59.0, @typescript-eslint/types@npm:^8.56.0, @typescript-eslint/types@npm:^8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/types@npm:8.59.0"
checksum: 10/51a773339c58a350d0ddaecba46ba735696f11829cab1f9b3d5d58a4bbd498693296ae742e3959d32f3bb29676c8e6bd120b970379d749a5a9b419393696930d
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/typescript-estree@npm:8.59.1"
"@typescript-eslint/typescript-estree@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/typescript-estree@npm:8.59.0"
dependencies:
"@typescript-eslint/project-service": "npm:8.59.1"
"@typescript-eslint/tsconfig-utils": "npm:8.59.1"
"@typescript-eslint/types": "npm:8.59.1"
"@typescript-eslint/visitor-keys": "npm:8.59.1"
"@typescript-eslint/project-service": "npm:8.59.0"
"@typescript-eslint/tsconfig-utils": "npm:8.59.0"
"@typescript-eslint/types": "npm:8.59.0"
"@typescript-eslint/visitor-keys": "npm:8.59.0"
debug: "npm:^4.4.3"
minimatch: "npm:^10.2.2"
semver: "npm:^7.7.3"
@@ -4489,32 +4489,32 @@ __metadata:
ts-api-utils: "npm:^2.5.0"
peerDependencies:
typescript: ">=4.8.4 <6.1.0"
checksum: 10/8ede99640ac8b08ac73905bbc66dd06b2c4dc211240a4a9cb532b0fcf5c36ec9e7639ed7e1c17f86a948499279ff93e9dbcdf9170661d9f8347fcb53e8266772
checksum: 10/48eba6a117a36c4bf569aa1a728463619b131a45a6891cc0a5d2454828d9d3d07a499e9906de0df31de57761ce1d13aebb635a059782f3cc16563e3e63a29713
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/utils@npm:8.59.1"
"@typescript-eslint/utils@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/utils@npm:8.59.0"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.9.1"
"@typescript-eslint/scope-manager": "npm:8.59.1"
"@typescript-eslint/types": "npm:8.59.1"
"@typescript-eslint/typescript-estree": "npm:8.59.1"
"@typescript-eslint/scope-manager": "npm:8.59.0"
"@typescript-eslint/types": "npm:8.59.0"
"@typescript-eslint/typescript-estree": "npm:8.59.0"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: ">=4.8.4 <6.1.0"
checksum: 10/26ae39a574e56d92b6fc406113e797c354fce8b377721cc5dd50579a0e9f8c3efe23c7693826ce2c16be96490520dd6ce7e145c4c39c22d8d00f2614791603ba
checksum: 10/70547510f16459ca29e207584676f7c15626b5f7e2562643144fe037a1a9c4ca7116be99e67b9045f0de60db0022affb58c34c553a5370276ff8f542f7b05732
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:8.59.1":
version: 8.59.1
resolution: "@typescript-eslint/visitor-keys@npm:8.59.1"
"@typescript-eslint/visitor-keys@npm:8.59.0":
version: 8.59.0
resolution: "@typescript-eslint/visitor-keys@npm:8.59.0"
dependencies:
"@typescript-eslint/types": "npm:8.59.1"
"@typescript-eslint/types": "npm:8.59.0"
eslint-visitor-keys: "npm:^5.0.0"
checksum: 10/5343f3424cafdcaf2550fade29eca6b86ad3f6ac953aef6ba1dccd39789a1c38520634fbbc0814419d9227f508789053c1c9f59c2841d72e56431c3fdd93ac65
checksum: 10/b81753b9ddddeb3564e44d1199ba5546028731c7b5b3270938525f1f2b549d1df5fa8f203d9b3eacc120fa6b5af314cb1fb69d3a12d1dcce18a52a0fe316628d
languageName: node
linkType: hard
@@ -8275,7 +8275,7 @@ __metadata:
tinykeys: "npm:3.0.0"
ts-lit-plugin: "npm:2.0.2"
typescript: "npm:6.0.3"
typescript-eslint: "npm:8.59.1"
typescript-eslint: "npm:8.59.0"
vite-tsconfig-paths: "npm:6.1.1"
vitest: "npm:4.1.5"
webpack-stats-plugin: "npm:1.1.3"
@@ -12568,18 +12568,18 @@ __metadata:
languageName: node
linkType: hard
"typescript-eslint@npm:8.59.1":
version: 8.59.1
resolution: "typescript-eslint@npm:8.59.1"
"typescript-eslint@npm:8.59.0":
version: 8.59.0
resolution: "typescript-eslint@npm:8.59.0"
dependencies:
"@typescript-eslint/eslint-plugin": "npm:8.59.1"
"@typescript-eslint/parser": "npm:8.59.1"
"@typescript-eslint/typescript-estree": "npm:8.59.1"
"@typescript-eslint/utils": "npm:8.59.1"
"@typescript-eslint/eslint-plugin": "npm:8.59.0"
"@typescript-eslint/parser": "npm:8.59.0"
"@typescript-eslint/typescript-estree": "npm:8.59.0"
"@typescript-eslint/utils": "npm:8.59.0"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: ">=4.8.4 <6.1.0"
checksum: 10/d35d30bdcff5b9644c9bf500d3ad74cebbd41612bf2669c3e3208cd74ee43302941666336acfca65bc44352b9b58c0455afe0a9e7106f12e54789b8c1f16dc11
checksum: 10/e015494cae2ae88c291e87d9d8c2c8d9924536f2edfac1a1da5e05f5ee083df7a8d916549f87af8a7b818d01de2bd505e29fdf991a086522a062387b4c2f1f64
languageName: node
linkType: hard