Compare commits

..

1 Commits

Author SHA1 Message Date
Paulus Schoutsen 854e56947f Update IFRAME_SANDBOX to remove 'allow-same-origin'
Removed 'allow-same-origin' from the IFRAME_SANDBOX settings.
2026-05-18 12:12:21 -04:00
18 changed files with 963 additions and 1120 deletions
+4 -3
View File
@@ -62,6 +62,7 @@
"@lit-labs/virtualizer": "2.1.1",
"@lit/context": "1.1.6",
"@lit/reactive-element": "2.1.2",
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
"@material/mwc-base": "0.27.0",
"@material/mwc-formfield": "patch:@material/mwc-formfield@npm%3A0.27.0#~/.yarn/patches/@material-mwc-formfield-npm-0.27.0-9528cb60f6.patch",
"@material/mwc-list": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
@@ -74,8 +75,8 @@
"@replit/codemirror-indentation-markers": "6.5.3",
"@swc/helpers": "0.5.21",
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "4.0.1",
"@tsparticles/preset-links": "4.0.1",
"@tsparticles/engine": "4.0.0",
"@tsparticles/preset-links": "4.0.0",
"@vibrant/color": "4.0.4",
"@webcomponents/scoped-custom-element-registry": "0.0.10",
"@webcomponents/webcomponentsjs": "2.8.0",
@@ -165,7 +166,7 @@
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.4",
"del": "8.0.1",
"eslint": "10.4.0",
"eslint": "10.3.0",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-webpack": "0.13.11",
"eslint-plugin-import-x": "4.16.2",
-3
View File
@@ -148,7 +148,6 @@ export interface GridSourceTypeEnergyPreference {
power_config?: PowerConfig;
cost_adjustment_day: number;
name?: string;
}
export interface SolarSourceTypeEnergyPreference {
@@ -157,7 +156,6 @@ export interface SolarSourceTypeEnergyPreference {
stat_energy_from: string;
stat_rate?: string;
config_entry_solar_forecast: string[] | null;
name?: string;
}
export interface BatterySourceTypeEnergyPreference {
@@ -167,7 +165,6 @@ export interface BatterySourceTypeEnergyPreference {
stat_rate?: string; // always available if power_config is set
power_config?: PowerConfig;
stat_soc?: string;
name?: string;
}
export interface GasSourceTypeEnergyPreference {
type: "gas";
@@ -200,13 +200,12 @@ class MoreInfoMediaPlayer extends LitElement {
protected _renderSourceControl() {
if (
!this.stateObj ||
!supportsFeature(this.stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
!supportsFeature(this.stateObj, MediaPlayerEntityFeature.SELECT_SOURCE) ||
!this.stateObj.attributes.source_list?.length
) {
return nothing;
}
const sourceList = this.stateObj.attributes.source_list || [];
return html`<ha-tooltip for="source-button">
${this.hass.localize(`ui.card.media_player.source`)}
</ha-tooltip>
@@ -218,7 +217,7 @@ class MoreInfoMediaPlayer extends LitElement {
.path=${mdiLoginVariant}
>
</ha-icon-button>
${sourceList.map(
${this.stateObj.attributes.source_list!.map(
(source) =>
html`<ha-dropdown-item
.value=${source}
@@ -1,6 +1,6 @@
import { mdiBatteryHigh, mdiDelete, mdiPencil, mdiPlus } from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-card";
@@ -100,24 +100,19 @@ export class EnergyBatterySettings extends LitElement {
></ha-svg-icon>`}
<div class="content">
<span class="label"
>${source.name ||
getStatisticLabel(
>${getStatisticLabel(
this.hass,
source.stat_energy_from,
this.statsMetadata?.[source.stat_energy_from]
)}</span
>
${source.name
? nothing
: html`
<span class="label"
>${getStatisticLabel(
this.hass,
source.stat_energy_to,
this.statsMetadata?.[source.stat_energy_to]
)}</span
>
`}
<span class="label"
>${getStatisticLabel(
this.hass,
source.stat_energy_to,
this.statsMetadata?.[source.stat_energy_to]
)}</span
>
</div>
<ha-icon-button
.label=${this.hass.localize(
@@ -158,7 +153,6 @@ export class EnergyBatterySettings extends LitElement {
private _addSource() {
showEnergySettingsBatteryDialog(this, {
statsMetadata: this.statsMetadata,
battery_sources: this.preferences.energy_sources.filter(
(src) => src.type === "battery"
) as BatterySourceTypeEnergyPreference[],
@@ -175,7 +169,6 @@ export class EnergyBatterySettings extends LitElement {
const origSource: BatterySourceTypeEnergyPreference =
ev.currentTarget.closest(".row").source;
showEnergySettingsBatteryDialog(this, {
statsMetadata: this.statsMetadata,
source: { ...origSource },
battery_sources: this.preferences.energy_sources.filter(
(src) => src.type === "battery"
@@ -124,16 +124,13 @@ export class EnergyGridSettings extends LitElement {
></ha-svg-icon>`}
<div class="content">
<span class="label"
>${source.name ||
getStatisticLabel(
>${getStatisticLabel(
this.hass,
primaryStat,
this.statsMetadata?.[primaryStat]
)}</span
>
${source.stat_energy_from &&
source.stat_energy_to &&
!source.name
${source.stat_energy_from && source.stat_energy_to
? html`<span class="label secondary"
>${getStatisticLabel(
this.hass,
@@ -269,7 +266,6 @@ export class EnergyGridSettings extends LitElement {
private _addSource() {
showEnergySettingsGridDialog(this, {
statsMetadata: this.statsMetadata,
grid_sources: this._getGridSources(),
saveCallback: async (source) => {
const preferences: EnergyPreferences = {
@@ -287,7 +283,6 @@ export class EnergyGridSettings extends LitElement {
const sourceIndex: number = row.sourceIndex;
showEnergySettingsGridDialog(this, {
statsMetadata: this.statsMetadata,
source: { ...origSource },
grid_sources: this._getGridSources(),
saveCallback: async (newSource) => {
@@ -101,8 +101,7 @@ export class EnergySolarSettings extends LitElement {
.path=${mdiSolarPower}
></ha-svg-icon>`}
<span class="content"
>${source.name ||
getStatisticLabel(
>${getStatisticLabel(
this.hass,
source.stat_energy_from,
this.statsMetadata?.[source.stat_energy_from]
@@ -155,7 +154,6 @@ export class EnergySolarSettings extends LitElement {
private _addSource() {
showEnergySettingsSolarDialog(this, {
statsMetadata: this.statsMetadata,
info: this.info!,
solar_sources: this.preferences.energy_sources.filter(
(src) => src.type === "solar"
@@ -173,7 +171,6 @@ export class EnergySolarSettings extends LitElement {
const origSource: SolarSourceTypeEnergyPreference =
ev.currentTarget.closest(".row").source;
showEnergySettingsSolarDialog(this, {
statsMetadata: this.statsMetadata,
info: this.info!,
source: { ...origSource },
solar_sources: this.preferences.energy_sources.filter(
@@ -6,7 +6,6 @@ import "../../../../components/entity/ha-statistic-picker";
import "../../../../components/ha-button";
import "../../../../components/ha-dialog";
import "../../../../components/ha-dialog-footer";
import "../../../../components/input/ha-input";
import type {
BatterySourceTypeEnergyPreference,
PowerConfig,
@@ -15,11 +14,6 @@ import {
emptyBatteryEnergyPreference,
energyStatisticHelpUrl,
} from "../../../../data/energy";
import {
getStatisticLabel,
getStatisticMetadata,
isExternalStatistic,
} from "../../../../data/recorder";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
import { haStyle, haStyleDialog } from "../../../../resources/styles";
@@ -33,7 +27,6 @@ import {
type PowerType,
} from "./ha-energy-power-config";
import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
import type { HaInput } from "../../../../components/input/ha-input";
const energyUnitClasses = ["energy"];
const socStatisticsUnits = ["%"];
@@ -181,32 +174,6 @@ export class DialogEnergyBatterySettings
)}
></ha-statistic-picker>
<ha-input
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.display_name"
)}
type="text"
.disabled=${!(
this._source?.stat_energy_from || this._source?.stat_energy_to
)}
.value=${this._source?.name || ""}
.placeholder=${this._source?.stat_energy_from
? getStatisticLabel(
this.hass,
this._source.stat_energy_from,
this._params?.statsMetadata?.[this._source.stat_energy_from]
)
: this._source?.stat_energy_to
? getStatisticLabel(
this.hass,
this._source.stat_energy_to,
this._params?.statsMetadata?.[this._source.stat_energy_to]
)
: ""}
@input=${this._nameChanged}
>
</ha-input>
<ha-energy-power-config
.hass=${this.hass}
.powerType=${this._powerType}
@@ -265,39 +232,12 @@ export class DialogEnergyBatterySettings
return true;
}
private async _updateMetadata(statId: string) {
if (
statId &&
isExternalStatistic(statId) &&
this._params?.statsMetadata &&
!(statId in this._params.statsMetadata)
) {
const [metadata] = await getStatisticMetadata(this.hass, [statId]);
if (metadata) {
this._params.statsMetadata[statId] = metadata;
this.requestUpdate("_params");
}
}
}
private _statisticToChanged(ev: ValueChangedEvent<string>) {
this._source = { ...this._source!, stat_energy_to: ev.detail.value };
this._updateMetadata(ev.detail.value);
}
private _statisticFromChanged(ev: ValueChangedEvent<string>) {
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
this._updateMetadata(ev.detail.value);
}
private _nameChanged(ev: InputEvent) {
this._source = {
...this._source!,
name: (ev.target as HaInput).value,
};
if (!this._source.name) {
delete this._source.name;
}
}
private _handlePowerConfigChanged(
@@ -321,9 +261,6 @@ export class DialogEnergyBatterySettings
stat_energy_from: this._source!.stat_energy_from,
stat_energy_to: this._source!.stat_energy_to,
};
if (this._source?.name) {
source.name = this._source.name;
}
// Only include power_config if a power type is selected
if (this._powerType !== "none") {
@@ -19,11 +19,7 @@ import {
emptyGridSourceEnergyPreference,
energyStatisticHelpUrl,
} from "../../../../data/energy";
import {
getStatisticLabel,
getStatisticMetadata,
isExternalStatistic,
} from "../../../../data/recorder";
import { isExternalStatistic } from "../../../../data/recorder";
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
import { haStyle, haStyleDialog } from "../../../../resources/styles";
@@ -37,7 +33,6 @@ import {
type PowerType,
} from "./ha-energy-power-config";
import type { EnergySettingsGridDialogParams } from "./show-dialogs-energy";
import type { HaInput } from "../../../../components/input/ha-input";
const energyUnitClasses = ["energy"];
@@ -229,33 +224,6 @@ export class DialogEnergyGridSettings
)}
></ha-statistic-picker>
<ha-input
class="name"
.label=${this.hass.localize(
"ui.panel.config.energy.grid.dialog.display_name"
)}
type="text"
.disabled=${!(
this._source?.stat_energy_from || this._source?.stat_energy_to
)}
.value=${this._source?.name || ""}
.placeholder=${this._source?.stat_energy_from
? getStatisticLabel(
this.hass,
this._source.stat_energy_from,
this._params?.statsMetadata?.[this._source.stat_energy_from]
)
: this._source?.stat_energy_to
? getStatisticLabel(
this.hass,
this._source.stat_energy_to,
this._params?.statsMetadata?.[this._source.stat_energy_to]
)
: ""}
@input=${this._nameChanged}
>
</ha-input>
<p class="section-label">
${this.hass.localize(
"ui.panel.config.energy.grid.dialog.import_cost"
@@ -476,21 +444,6 @@ export class DialogEnergyGridSettings
return true;
}
private async _updateMetadata(statId: string) {
if (
statId &&
isExternalStatistic(statId) &&
this._params?.statsMetadata &&
!(statId in this._params.statsMetadata)
) {
const [metadata] = await getStatisticMetadata(this.hass, [statId]);
if (metadata) {
this._params.statsMetadata[statId] = metadata;
this.requestUpdate("_params");
}
}
}
private _statisticFromChanged(ev: ValueChangedEvent<string>) {
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
// Reset cost type if switching to external statistic with incompatible cost type
@@ -506,7 +459,6 @@ export class DialogEnergyGridSettings
number_energy_price: null,
};
}
this._updateMetadata(ev.detail.value);
}
private _statisticToChanged(ev: ValueChangedEvent<string>) {
@@ -535,17 +487,6 @@ export class DialogEnergyGridSettings
number_energy_price_export: null,
};
}
this._updateMetadata(ev.detail.value);
}
private _nameChanged(ev: InputEvent) {
this._source = {
...this._source!,
name: (ev.target as HaInput).value,
};
if (!this._source.name) {
delete this._source.name;
}
}
private _handleImportCostTypeChanged(ev: Event) {
@@ -628,9 +569,6 @@ export class DialogEnergyGridSettings
number_energy_price_export: this._source!.number_energy_price_export,
cost_adjustment_day: this._source!.cost_adjustment_day,
};
if (this._source?.name) {
source.name = this._source.name;
}
// Only include power_config if a power type is selected
if (this._powerType !== "none") {
@@ -663,9 +601,6 @@ export class DialogEnergyGridSettings
ha-input:last-of-type {
margin-bottom: 0;
}
ha-input.name {
margin-top: var(--ha-space-4);
}
ha-radio-group {
margin-bottom: var(--ha-space-4);
}
@@ -11,7 +11,6 @@ import "../../../../components/ha-dialog";
import "../../../../components/ha-dialog-footer";
import "../../../../components/ha-svg-icon";
import "../../../../components/radio/ha-radio-group";
import "../../../../components/input/ha-input";
import type { HaRadioGroup } from "../../../../components/radio/ha-radio-group";
import "../../../../components/radio/ha-radio-option";
import type { ConfigEntry } from "../../../../data/config_entries";
@@ -28,12 +27,6 @@ import { haStyle, haStyleDialog } from "../../../../resources/styles";
import type { HomeAssistant, ValueChangedEvent } from "../../../../types";
import { brandsUrl } from "../../../../util/brands-url";
import type { EnergySettingsSolarDialogParams } from "./show-dialogs-energy";
import {
getStatisticLabel,
getStatisticMetadata,
isExternalStatistic,
} from "../../../../data/recorder";
import type { HaInput } from "../../../../components/input/ha-input";
const energyUnitClasses = ["energy"];
const powerUnitClasses = ["power"];
@@ -136,24 +129,6 @@ export class DialogEnergySolarSettings
autofocus
></ha-statistic-picker>
<ha-input
.label=${this.hass.localize(
"ui.panel.config.energy.solar.dialog.display_name"
)}
type="text"
.disabled=${!this._source?.stat_energy_from}
.value=${this._source?.name || ""}
.placeholder=${this._source?.stat_energy_from
? getStatisticLabel(
this.hass,
this._source.stat_energy_from,
this._params?.statsMetadata?.[this._source.stat_energy_from]
)
: ""}
@input=${this._nameChanged}
>
</ha-input>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
@@ -309,38 +284,14 @@ export class DialogEnergySolarSettings
});
}
private async _statisticChanged(ev: ValueChangedEvent<string>) {
private _statisticChanged(ev: ValueChangedEvent<string>) {
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
if (
ev.detail.value &&
isExternalStatistic(ev.detail.value) &&
this._params?.statsMetadata &&
!(ev.detail.value in this._params.statsMetadata)
) {
const [metadata] = await getStatisticMetadata(this.hass, [
ev.detail.value,
]);
if (metadata) {
this._params.statsMetadata[ev.detail.value] = metadata;
this.requestUpdate("_params");
}
}
}
private _powerStatisticChanged(ev: ValueChangedEvent<string>) {
this._source = { ...this._source!, stat_rate: ev.detail.value };
}
private _nameChanged(ev: InputEvent) {
this._source = {
...this._source!,
name: (ev.target as HaInput).value,
};
if (!this._source.name) {
delete this._source.name;
}
}
private async _save() {
try {
if (!this._forecast) {
@@ -14,7 +14,6 @@ import type { StatisticsMetaData } from "../../../../data/recorder";
export interface EnergySettingsGridDialogParams {
source?: GridSourceTypeEnergyPreference;
grid_sources: GridSourceTypeEnergyPreference[];
statsMetadata?: Record<string, StatisticsMetaData>;
saveCallback: (source: GridSourceTypeEnergyPreference) => Promise<void>;
}
@@ -22,14 +21,12 @@ export interface EnergySettingsSolarDialogParams {
info: EnergyInfo;
source?: SolarSourceTypeEnergyPreference;
solar_sources: SolarSourceTypeEnergyPreference[];
statsMetadata?: Record<string, StatisticsMetaData>;
saveCallback: (source: SolarSourceTypeEnergyPreference) => Promise<void>;
}
export interface EnergySettingsBatteryDialogParams {
source?: BatterySourceTypeEnergyPreference;
battery_sources: BatterySourceTypeEnergyPreference[];
statsMetadata?: Record<string, StatisticsMetaData>;
saveCallback: (source: BatterySourceTypeEnergyPreference) => Promise<void>;
}
@@ -26,7 +26,8 @@ export const supportsMediaPlayerSourceCardFeature = (
const domain = computeDomain(stateObj.entity_id);
return (
domain === "media_player" &&
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE) &&
!!stateObj.attributes.source_list?.length
);
};
@@ -355,13 +355,11 @@ export class HuiEnergySolarGraphCard
name: this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_solar_graph.production",
{
name:
source.name ||
getStatisticLabel(
this.hass,
source.stat_energy_from,
statisticsMetaData[source.stat_energy_from]
),
name: getStatisticLabel(
this.hass,
source.stat_energy_from,
statisticsMetaData[source.stat_energy_from]
),
}
),
barMaxWidth: 50,
@@ -465,13 +463,11 @@ export class HuiEnergySolarGraphCard
name: this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_solar_graph.forecast",
{
name:
source.name ||
getStatisticLabel(
this.hass,
source.stat_energy_from,
statisticsMetaData[source.stat_energy_from]
),
name: getStatisticLabel(
this.hass,
source.stat_energy_from,
statisticsMetaData[source.stat_energy_from]
),
}
),
step: false,
@@ -1,6 +1,8 @@
// @ts-ignore
import dataTableStyles from "@material/data-table/dist/mdc.data-table.min.css";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { css, html, LitElement, unsafeCSS, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
@@ -549,13 +551,7 @@ export class HuiEnergySourcesTableCard
null,
null,
showCosts,
compare,
source.name
? this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_discharged",
{ name: source.name }
)
: ""
compare
)}${this._renderRow(
computedStyles,
"battery_in",
@@ -567,13 +563,7 @@ export class HuiEnergySourcesTableCard
null,
null,
showCosts,
compare,
source.name
? this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_charged",
{ name: source.name }
)
: ""
compare
)}`;
})}
${types.battery
@@ -640,15 +630,6 @@ export class HuiEnergySourcesTableCard
return nothing;
}
const name = !source.name
? ""
: source.stat_energy_to
? this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_sources_table.named_grid_imported",
{ name: source.name }
)
: source.name;
return this._renderRow(
computedStyles,
"grid_consumption",
@@ -660,8 +641,7 @@ export class HuiEnergySourcesTableCard
cost,
costCompare,
showCosts,
compare,
name
compare
);
})();
@@ -690,15 +670,6 @@ export class HuiEnergySourcesTableCard
return nothing;
}
const name = !source.name
? ""
: source.stat_energy_from
? this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_sources_table.named_grid_exported",
{ name: source.name }
)
: source.name;
return this._renderRow(
computedStyles,
"grid_return",
@@ -710,8 +681,7 @@ export class HuiEnergySourcesTableCard
-cost,
-costCompare,
showCosts,
compare,
name
compare
);
})();
@@ -786,120 +756,63 @@ export class HuiEnergySourcesTableCard
}
}
static styles: CSSResultGroup = css`
.mdc-data-table__content,
.mdc-data-table__cell {
font-family: var(--ha-font-family-body);
-moz-osx-font-smoothing: var(--ha-moz-osx-font-smoothing);
-webkit-font-smoothing: var(--ha-font-smoothing);
font-size: var(--ha-font-size-m);
line-height: var(--ha-line-height-normal);
font-weight: var(--ha-font-weight-normal);
letter-spacing: 0.0178571429em;
text-decoration: inherit;
text-transform: inherit;
}
.mdc-data-table {
background-color: var(--card-background-color);
border-radius: var(--ha-border-radius-sm);
border: 0;
box-sizing: border-box;
display: inline-flex;
flex-direction: column;
position: relative;
width: 100%;
}
.mdc-data-table__table-container {
-webkit-overflow-scrolling: touch;
overflow-x: auto;
width: 100%;
}
.mdc-data-table__table {
min-width: 100%;
border: 0;
border-spacing: 0;
table-layout: fixed;
white-space: nowrap;
}
.mdc-data-table__header-row {
height: 56px;
}
.mdc-data-table__row {
background-color: inherit;
height: 52px;
}
.mdc-data-table__header-cell,
.mdc-data-table__cell {
border-bottom-width: 1px;
border-bottom-style: solid;
box-sizing: border-box;
color: var(--primary-text-color);
border-bottom-color: var(--divider-color);
overflow: hidden;
padding: 0 16px;
text-align: var(--float-start);
text-overflow: ellipsis;
}
.mdc-data-table__header-cell {
background-color: var(--card-background-color);
font-family: var(--ha-font-family-body);
-moz-osx-font-smoothing: var(--ha-moz-osx-font-smoothing);
-webkit-font-smoothing: var(--ha-font-smoothing);
font-size: var(--ha-font-size-m);
line-height: var(--ha-line-height-normal);
font-weight: var(--ha-font-weight-medium);
letter-spacing: 0.0071428571em;
text-decoration: inherit;
text-transform: inherit;
}
.mdc-data-table__row:last-child .mdc-data-table__cell {
border-bottom: none;
}
.mdc-data-table__row:not(.mdc-data-table__row--selected):hover {
background-color: rgba(var(--rgb-primary-text-color), 0.04);
}
.clickable {
cursor: pointer;
}
.total .mdc-data-table__cell {
border-top: 1px solid var(--divider-color);
font-weight: var(--ha-font-weight-medium);
}
ha-card {
max-height: 100%;
overflow: auto;
}
.card-header {
padding-bottom: 0;
}
.content {
padding: 16px;
}
.has-header {
padding-top: 0;
}
.cell-bullet {
width: 32px;
padding-right: 0;
padding-inline-end: 0;
padding-inline-start: 16px;
direction: var(--direction);
}
.bullet {
border-width: 1px;
border-style: solid;
border-radius: var(--ha-border-radius-sm);
height: 16px;
width: 32px;
}
.mdc-data-table__cell--numeric {
text-align: var(--float-end);
direction: ltr;
}
.mdc-data-table__header-cell--numeric {
text-align: var(--float-end);
}
`;
static get styles(): CSSResultGroup {
return css`
${unsafeCSS(dataTableStyles)}
.mdc-data-table {
width: 100%;
border: 0;
}
.mdc-data-table__header-cell,
.mdc-data-table__cell {
color: var(--primary-text-color);
border-bottom-color: var(--divider-color);
text-align: var(--float-start);
}
.mdc-data-table__row:not(.mdc-data-table__row--selected):hover {
background-color: rgba(var(--rgb-primary-text-color), 0.04);
}
.clickable {
cursor: pointer;
}
.total {
--mdc-typography-body2-font-weight: var(--ha-font-weight-medium);
}
.total .mdc-data-table__cell {
border-top: 1px solid var(--divider-color);
}
ha-card {
max-height: 100%;
overflow: auto;
}
.card-header {
padding-bottom: 0;
}
.content {
padding: 16px;
}
.has-header {
padding-top: 0;
}
.cell-bullet {
width: 32px;
padding-right: 0;
padding-inline-end: 0;
padding-inline-start: 16px;
direction: var(--direction);
}
.bullet {
border-width: 1px;
border-style: solid;
border-radius: var(--ha-border-radius-sm);
height: 16px;
width: 32px;
}
.mdc-data-table__cell--numeric {
direction: ltr;
}
`;
}
}
declare global {
@@ -259,16 +259,6 @@ export class HuiEnergyUsageGraphCard
from_battery?: string[];
} = {};
const statLabels: {
to_grid: Record<string, string>;
from_grid: Record<string, string>;
to_battery: Record<string, string>;
} = {
to_grid: {},
from_grid: {},
to_battery: {},
};
for (const source of energyData.prefs.energy_sources) {
if (source.type === "solar") {
if (statIds.solar) {
@@ -287,12 +277,6 @@ export class HuiEnergyUsageGraphCard
statIds.to_battery = [source.stat_energy_to];
statIds.from_battery = [source.stat_energy_from];
}
if (source.name) {
statLabels.to_battery[source.stat_energy_to] = this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_charged",
{ name: source.name }
);
}
continue;
}
@@ -307,15 +291,6 @@ export class HuiEnergyUsageGraphCard
} else {
statIds.from_grid = [gridSource.stat_energy_from];
}
if (gridSource.name) {
statLabels.from_grid[gridSource.stat_energy_from] =
gridSource.stat_energy_to
? this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_usage_graph.named_grid_consumed",
{ name: gridSource.name }
)
: gridSource.name;
}
}
if (gridSource.stat_energy_to) {
if (statIds.to_grid) {
@@ -323,15 +298,6 @@ export class HuiEnergyUsageGraphCard
} else {
statIds.to_grid = [gridSource.stat_energy_to];
}
if (gridSource.name) {
statLabels.to_grid[gridSource.stat_energy_to] =
gridSource.stat_energy_from
? this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_usage_graph.named_grid_exported",
{ name: gridSource.name }
)
: gridSource.name;
}
}
}
@@ -354,7 +320,7 @@ export class HuiEnergyUsageGraphCard
}
});
const typeLabels = {
const labels = {
used_grid: this.hass.localize(
"ui.panel.lovelace.cards.energy.energy_usage_graph.combined_from_grid"
),
@@ -388,8 +354,7 @@ export class HuiEnergyUsageGraphCard
statIds,
colorIndices,
computedStyles,
typeLabels,
statLabels,
labels,
trackY,
true
)
@@ -416,8 +381,7 @@ export class HuiEnergyUsageGraphCard
statIds,
colorIndices,
computedStyles,
typeLabels,
statLabels,
labels,
trackY,
false
)
@@ -451,16 +415,11 @@ export class HuiEnergyUsageGraphCard
},
colorIndices: Record<string, Record<string, number>>,
computedStyles: CSSStyleDeclaration,
typeLabels: {
labels: {
used_grid: string;
used_solar: string;
used_battery: string;
},
statLabels: {
to_grid: Record<string, string>;
from_grid: Record<string, string>;
to_battery: Record<string, string>;
},
trackY: (v: number) => void,
compare = false
) {
@@ -581,10 +540,9 @@ export class HuiEnergyUsageGraphCard
type: "bar",
cursor: "default",
name:
type in typeLabels
? typeLabels[type]
: statLabels[type]?.[statId] ||
getStatisticLabel(
type in labels
? labels[type]
: getStatisticLabel(
this.hass,
statId,
statisticsMetaData[statId]
@@ -61,11 +61,10 @@ export const securityEntityFilters: EntityFilter[] = [
],
entity_category: "none",
},
// We also want the tamper and moisture sensors when they are diagnostic
// (some integrations, e.g. homee, mark water leak alarms as diagnostic)
// We also want the tamper sensors when they are diagnostic
{
domain: "binary_sensor",
device_class: ["moisture", "tamper"],
device_class: ["tamper"],
entity_category: "diagnostic",
},
];
+3 -13
View File
@@ -1751,7 +1751,7 @@
"no_areas_text_non_admin": "Ask an administrator to map your vacuum's segments to areas.",
"configure_area_mapping": "Configure area mapping",
"configure": "Configure",
"clean_areas_order_hint": "The order in which areas are cleaned may not be supported by your vacuum.",
"clean_areas_order_hint": "Cleaning order may not be supported by your vacuum.",
"other_areas": "Other areas"
},
"person": {
@@ -4115,7 +4115,6 @@
"energy_from_helper": "Pick a sensor which measures grid import in either of {unit}.",
"energy_to_grid": "Energy exported to grid",
"energy_to_helper": "Pick a sensor which measures grid export in either of {unit}.",
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
"import_cost": "Cost tracking",
"import_cost_para": "Select how Home Assistant should keep track of the costs of the imported energy.",
"no_cost_tracking": "Do not track costs",
@@ -4173,7 +4172,6 @@
"dialog": {
"header": "Configure solar panels",
"entity_para": "Pick a sensor which measures solar production in either of {unit}.",
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
"solar_production_energy": "Solar production energy",
"solar_production_power": "Solar production power",
"solar_production_forecast": "Solar production forecast",
@@ -4197,7 +4195,6 @@
"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",
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
"state_of_charge": "Battery state of charge sensor",
"state_of_charge_helper": "Sensor reporting battery state of charge as %.",
"power": "Battery power",
@@ -8573,10 +8570,7 @@
"total_usage": "+{num} kWh",
"combined_from_grid": "Combined from grid",
"consumed_solar": "Consumed solar",
"consumed_battery": "Consumed battery",
"named_battery_charged": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_battery_charged%]",
"named_grid_consumed": "Consumed {name}",
"named_grid_exported": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_grid_exported%]"
"consumed_battery": "Consumed battery"
},
"energy_sources_table": {
"grid_total": "Grid total",
@@ -8589,11 +8583,7 @@
"previous_energy": "Previous usage",
"previous_cost": "Previous cost",
"battery_total": "Battery total",
"total_costs": "Total costs",
"named_battery_charged": "{name} charged",
"named_battery_discharged": "{name} discharged",
"named_grid_imported": "{name} imported",
"named_grid_exported": "{name} exported"
"total_costs": "Total costs"
},
"energy_solar_graph": {
"production": "Production {name}",
+1 -1
View File
@@ -1,2 +1,2 @@
export const IFRAME_SANDBOX =
"allow-forms allow-popups allow-pointer-lock allow-same-origin allow-scripts allow-modals allow-downloads";
"allow-forms allow-popups allow-pointer-lock allow-scripts allow-modals allow-downloads";
+853 -669
View File
File diff suppressed because it is too large Load Diff