Compare commits

..

1 Commits

Author SHA1 Message Date
Simon Lamon
fd2cac5af9 Increase thickness for accessability reasons 2026-04-02 16:21:15 +00:00
24 changed files with 142 additions and 385 deletions

View File

@@ -1,4 +1,3 @@
/// <reference types="chromecast-caf-sender" />
import { mdiTelevision } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, state } from "lit/decorators";

View File

@@ -207,7 +207,7 @@
"tar": "7.5.13",
"terser-webpack-plugin": "5.4.0",
"ts-lit-plugin": "2.0.2",
"typescript": "6.0.2",
"typescript": "5.9.3",
"typescript-eslint": "8.57.2",
"vite-tsconfig-paths": "6.1.1",
"vitest": "4.1.2",

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-console */
/// <reference types="chromecast-caf-sender" />
import type { Auth } from "home-assistant-js-websocket";
import { castApiAvailable } from "./cast_framework";

View File

@@ -38,14 +38,6 @@ export interface HASSDomEvent<T> extends Event {
detail: T;
}
export type HASSDomTargetEvent<T extends EventTarget> = Event & {
target: T;
};
export type HASSDomCurrentTargetEvent<T extends EventTarget> = Event & {
currentTarget: T;
};
/**
* Dispatches a custom event with an optional detail value.
*

View File

@@ -606,7 +606,13 @@ export class HaChartBase extends LitElement {
id: "dataZoom",
type: "inside",
orient: "horizontal",
filterMode: this._getDataZoomFilterMode() as any,
// "boundaryFilter" is a custom mode added via axis-proxy-patch.ts.
// It rescales the Y-axis to the visible data while keeping one point
// just outside each boundary to avoid line gaps at the zoom edges.
// Only use it for line charts — it causes issues with bar charts.
filterMode: (ensureArray(this.data).every((s) => s.type === "line")
? "boundaryFilter"
: "filter") as any,
xAxisIndex: 0,
moveOnMouseMove: !this._isTouchDevice || this._isZoomed,
preventDefaultMouseMove: !this._isTouchDevice || this._isZoomed,
@@ -614,23 +620,6 @@ export class HaChartBase extends LitElement {
};
}
// "boundaryFilter" is a custom mode added via axis-proxy-patch.ts.
// It rescales the Y-axis to the visible data while keeping one point
// just outside each boundary to avoid line gaps at the zoom edges.
// Use "filter" for bar charts since boundaryFilter causes rendering issues.
// Use "weakFilter" for other types (e.g. custom/timeline) so bars
// spanning the visible range boundary are kept.
private _getDataZoomFilterMode(): string {
const series = ensureArray(this.data);
if (series.every((s) => s.type === "line")) {
return "boundaryFilter";
}
if (series.some((s) => s.type === "bar")) {
return "filter";
}
return "weakFilter";
}
private _createOptions(): ECOption {
let xAxis = this.options?.xAxis;
if (xAxis) {

View File

@@ -17,10 +17,6 @@ import memoizeOne from "memoize-one";
import { STRINGS_SEPARATOR_DOT } from "../../common/const";
import { restoreScroll } from "../../common/decorators/restore-scroll";
import { fireEvent } from "../../common/dom/fire_event";
import type {
HASSDomCurrentTargetEvent,
HASSDomTargetEvent,
} from "../../common/dom/fire_event";
import { stringCompare } from "../../common/string/compare";
import type { LocalizeFunc } from "../../common/translations/localize";
import { debounce } from "../../common/util/debounce";
@@ -107,7 +103,6 @@ export interface DataTableRowData {
export type SortableColumnContainer = Record<string, ClonedDataTableColumnData>;
const UNDEFINED_GROUP_KEY = "zzzzz_undefined";
const AUTO_FOCUS_ALLOWED_ACTIVE_TAGS = ["BODY", "HTML", "HOME-ASSISTANT"];
@customElement("ha-data-table")
export class HaDataTable extends LitElement {
@@ -171,10 +166,6 @@ export class HaDataTable extends LitElement {
@query("slot[name='header']") private _header!: HTMLSlotElement;
@query(".mdc-data-table__header-row") private _headerRow?: HTMLDivElement;
@query("lit-virtualizer") private _scroller?: HTMLElement;
@state() private _collapsedGroups: string[] = [];
@state() private _lastSelectedRowId: string | null = null;
@@ -189,8 +180,6 @@ export class HaDataTable extends LitElement {
private _lastUpdate = 0;
private _didAutoFocusScroller = false;
// @ts-ignore
@restoreScroll(".scroller") private _savedScrollPos?: number;
@@ -253,26 +242,16 @@ export class HaDataTable extends LitElement {
this.updateComplete.then(() => this._calcTableHeight());
}
protected updated(changedProps: PropertyValues) {
if (!this._headerRow) {
protected updated() {
const header = this.renderRoot.querySelector(".mdc-data-table__header-row");
if (!header) {
return;
}
if (this._headerRow.scrollWidth > this._headerRow.clientWidth) {
this.style.setProperty(
"--table-row-width",
`${this._headerRow.scrollWidth}px`
);
if (header.scrollWidth > header.clientWidth) {
this.style.setProperty("--table-row-width", `${header.scrollWidth}px`);
} else {
this.style.removeProperty("--table-row-width");
}
this._focusTableOnLoad();
// Refocus on toggle checkbox changes
if (changedProps.has("selectable")) {
this._focusScroller();
}
}
public willUpdate(properties: PropertyValues) {
@@ -538,7 +517,6 @@ export class HaDataTable extends LitElement {
<lit-virtualizer
scroller
class="mdc-data-table__content scroller ha-scrollbar"
tabindex=${ifDefined(!this.autoHeight ? "0" : undefined)}
@scroll=${this._saveScrollPos}
.items=${this._groupData(
this._filteredData,
@@ -851,10 +829,8 @@ export class HaDataTable extends LitElement {
): Promise<DataTableRowData[]> => filterData(data, columns, filter)
);
private _handleHeaderClick(
ev: HASSDomCurrentTargetEvent<HTMLElement & { columnId: string }>
) {
const columnId = ev.currentTarget.columnId;
private _handleHeaderClick(ev: Event) {
const columnId = (ev.currentTarget as any).columnId;
if (!this.columns[columnId].sortable) {
return;
}
@@ -872,12 +848,11 @@ export class HaDataTable extends LitElement {
column: columnId,
direction: this.sortDirection,
});
this._focusScroller();
}
private _handleHeaderRowCheckboxClick(ev: HASSDomTargetEvent<HaCheckbox>) {
if (ev.target.checked) {
private _handleHeaderRowCheckboxClick(ev: Event) {
const checkbox = ev.target as HaCheckbox;
if (checkbox.checked) {
this.selectAll();
} else {
this._checkedRows = [];
@@ -886,10 +861,9 @@ export class HaDataTable extends LitElement {
this._lastSelectedRowId = null;
}
private _handleRowCheckboxClicked = (
ev: HASSDomCurrentTargetEvent<HaCheckbox & { rowId: string }>
) => {
const rowId = ev.currentTarget.rowId;
private _handleRowCheckboxClicked = (ev: Event) => {
const checkbox = ev.currentTarget as HaCheckbox;
const rowId = (checkbox as any).rowId;
const groupedData = this._groupData(
this._filteredData,
@@ -926,7 +900,7 @@ export class HaDataTable extends LitElement {
...this._selectRange(groupedData, lastSelectedRowIndex, rowIndex),
];
}
} else if (!ev.currentTarget.checked) {
} else if (!checkbox.checked) {
if (!this._checkedRows.includes(rowId)) {
this._checkedRows = [...this._checkedRows, rowId];
}
@@ -964,9 +938,7 @@ export class HaDataTable extends LitElement {
return checkedRows;
}
private _handleRowClick = (
ev: HASSDomCurrentTargetEvent<HTMLElement & { rowId: string }>
) => {
private _handleRowClick = (ev: Event) => {
if (
ev
.composedPath()
@@ -982,13 +954,14 @@ export class HaDataTable extends LitElement {
) {
return;
}
const rowId = ev.currentTarget.rowId;
const rowId = (ev.currentTarget as any).rowId;
fireEvent(this, "row-click", { id: rowId }, { bubbles: false });
};
private _setTitle(ev: HASSDomCurrentTargetEvent<HTMLElement>) {
if (ev.currentTarget.scrollWidth > ev.currentTarget.offsetWidth) {
ev.currentTarget.setAttribute("title", ev.currentTarget.innerText);
private _setTitle(ev: Event) {
const target = ev.currentTarget as HTMLElement;
if (target.scrollWidth > target.offsetWidth) {
target.setAttribute("title", target.innerText);
}
}
@@ -1010,27 +983,6 @@ export class HaDataTable extends LitElement {
this._debounceSearch((ev.target as HTMLInputElement).value);
}
private _focusTableOnLoad() {
if (
this._didAutoFocusScroller ||
this.autoHeight ||
(document.activeElement &&
!AUTO_FOCUS_ALLOWED_ACTIVE_TAGS.includes(
document.activeElement.tagName
))
) {
return;
}
this._focusScroller();
}
private _focusScroller(): void {
this._scroller?.focus({
preventScroll: true,
});
}
private async _calcTableHeight() {
if (this.autoHeight) {
return;
@@ -1040,27 +992,23 @@ export class HaDataTable extends LitElement {
}
@eventOptions({ passive: true })
private _saveScrollPos(e: HASSDomTargetEvent<HTMLDivElement>) {
this._savedScrollPos = e.target.scrollTop;
private _saveScrollPos(e: Event) {
this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;
if (this._headerRow) {
this._headerRow.scrollLeft = e.target.scrollLeft;
}
this.renderRoot.querySelector(".mdc-data-table__header-row")!.scrollLeft = (
e.target as HTMLDivElement
).scrollLeft;
}
@eventOptions({ passive: true })
private _scrollContent(e: HASSDomTargetEvent<HTMLDivElement>) {
if (!this._scroller) {
return;
}
this._scroller.scrollLeft = e.target.scrollLeft;
private _scrollContent(e: Event) {
this.renderRoot.querySelector("lit-virtualizer")!.scrollLeft = (
e.target as HTMLDivElement
).scrollLeft;
}
private _collapseGroup = (
ev: HASSDomCurrentTargetEvent<HTMLElement & { group: string }>
) => {
const groupName = ev.currentTarget.group;
private _collapseGroup = (ev: Event) => {
const groupName = (ev.currentTarget as any).group;
if (this._collapsedGroups.includes(groupName)) {
this._collapsedGroups = this._collapsedGroups.filter(
(grp) => grp !== groupName
@@ -1483,11 +1431,6 @@ export class HaDataTable extends LitElement {
contain: size layout !important;
overscroll-behavior: contain;
}
lit-virtualizer:focus,
lit-virtualizer:focus-visible {
outline: none;
}
`,
];
}

View File

@@ -171,7 +171,7 @@ export class HaGauge extends LitElement {
? svg`
<path
class="needle"
d="M -36,-2 L -44,-1 A 1,1,0,0,0,-44,1 L -36,2 A 2,2,0,0,0,-36,-2 Z"
d="M -34,-3 L -48,-1 A 1,1,0,0,0,-48,1 L -34,3 A 2,2,0,0,0,-34,-3 Z"
style=${styleMap({ transform: `rotate(${this._angle}deg)` })}
/>
@@ -243,19 +243,19 @@ export class HaGauge extends LitElement {
.levels-base {
fill: none;
stroke: var(--primary-background-color);
stroke-width: 6;
stroke-width: 12;
stroke-linecap: butt;
}
.level {
fill: none;
stroke-width: 6;
stroke-width: 12;
stroke-linecap: butt;
}
.value {
fill: none;
stroke-width: 6;
stroke-width: 12;
stroke: var(--gauge-color);
stroke-linecap: butt;
transition: stroke-dashoffset 1s ease 0s;

View File

@@ -630,7 +630,7 @@ export class HaInput extends LitElement {
}
wa-input::part(hint) {
min-height: var(--ha-space-5);
height: var(--ha-space-5);
margin-block-start: 0;
margin-inline-start: var(--ha-space-3);
font-size: var(--ha-font-size-xs);
@@ -641,7 +641,6 @@ export class HaInput extends LitElement {
wa-input.hint-hidden::part(hint) {
height: 0;
min-height: 0;
}
.error {

View File

@@ -826,16 +826,16 @@ const describeLegacyTrigger = (
: trigger.entity_id;
let offsetChoice = "other";
let offset = "";
let offset: string | string[] = "";
if (trigger.offset) {
offsetChoice = trigger.offset.startsWith("-") ? "before" : "after";
const parts = trigger.offset.startsWith("-")
offset = trigger.offset.startsWith("-")
? trigger.offset.substring(1).split(":")
: trigger.offset.split(":");
const duration = {
hours: parts.length > 0 ? +parts[0] : 0,
minutes: parts.length > 1 ? +parts[1] : 0,
seconds: parts.length > 2 ? +parts[2] : 0,
hours: offset.length > 0 ? +offset[0] : 0,
minutes: offset.length > 1 ? +offset[1] : 0,
seconds: offset.length > 2 ? +offset[2] : 0,
};
offset = formatDurationLong(hass.locale, duration);
if (offset === "") {

View File

@@ -20,7 +20,6 @@ export interface CoreFrontendSystemData {
export interface HomeFrontendSystemData {
favorite_entities?: string[];
welcome_banner_dismissed?: boolean;
hidden_summaries?: string[];
}
declare global {

View File

@@ -103,6 +103,7 @@ class DialogRestart extends LitElement {
return nothing;
}
const showReload = this.hass.userData?.showAdvanced;
const showRebootShutdown = !!this._hostInfo;
const dialogTitle = this.hass.localize("ui.dialogs.restart.heading");
@@ -134,24 +135,30 @@ class DialogRestart extends LitElement {
`
: html`
<ha-md-list dialogInitialFocus>
<ha-md-list-item
type="button"
@click=${this._reload}
.disabled=${this._loadingBackupInfo}
>
<div slot="headline">
${this.hass.localize("ui.dialogs.restart.reload.title")}
</div>
<div slot="supporting-text">
${this.hass.localize(
"ui.dialogs.restart.reload.description"
)}
</div>
<div slot="start" class="icon-background reload">
<ha-svg-icon .path=${mdiAutoFix}></ha-svg-icon>
</div>
<ha-icon-next slot="end"></ha-icon-next>
</ha-md-list-item>
${showReload
? html`
<ha-md-list-item
type="button"
@click=${this._reload}
.disabled=${this._loadingBackupInfo}
>
<div slot="headline">
${this.hass.localize(
"ui.dialogs.restart.reload.title"
)}
</div>
<div slot="supporting-text">
${this.hass.localize(
"ui.dialogs.restart.reload.description"
)}
</div>
<div slot="start" class="icon-background reload">
<ha-svg-icon .path=${mdiAutoFix}></ha-svg-icon>
</div>
<ha-icon-next slot="end"></ha-icon-next>
</ha-md-list-item>
`
: nothing}
<ha-md-list-item
type="button"
.action=${"restart"}

View File

@@ -107,6 +107,19 @@ class HaPanelDevAction extends LitElement {
this._yamlEditor?.setValue(this._serviceData)
);
}
} else if (!this._serviceData?.action) {
const domain = Object.keys(this.hass.services).sort()[0];
const service = Object.keys(this.hass.services[domain]).sort()[0];
this._serviceData = {
action: `${domain}.${service}`,
target: {},
data: {},
};
if (this._yamlMode) {
this.updateComplete.then(() =>
this._yamlEditor?.setValue(this._serviceData)
);
}
}
this._checkUiSupported();
}

View File

@@ -176,14 +176,13 @@ export class HaConfigDevicePage extends LitElement {
private _entities = memoizeOne(
(
deviceId: string,
entities: EntityRegistryEntry[],
devices: HomeAssistant["devices"]
entities: EntityRegistryEntry[]
): EntityRegistryStateEntry[] =>
entities
.filter((entity) => entity.device_id === deviceId)
.map((entity) => ({
...entity,
stateName: this._computeEntityName(entity, devices),
stateName: this._computeEntityName(entity),
}))
.sort((ent1, ent2) =>
stringCompare(
@@ -341,11 +340,7 @@ export class HaConfigDevicePage extends LitElement {
this.entries,
this.manifests
);
const entities = this._entities(
this.deviceId,
this._entityReg,
this.hass.devices
);
const entities = this._entities(this.deviceId, this._entityReg);
const entitiesByCategory = this._entitiesByCategory(entities);
const batteryEntity = this._batteryEntity(entities);
const batteryChargingEntity = this._batteryChargingEntity(entities);
@@ -1149,11 +1144,7 @@ export class HaConfigDevicePage extends LitElement {
});
}
const entities = this._entities(
this.deviceId,
this._entityReg,
this.hass.devices
);
const entities = this._entities(this.deviceId, this._entityReg);
const assistSatellite = entities.find(
(ent) => computeDomain(ent.entity_id) === "assist_satellite"
@@ -1280,13 +1271,10 @@ export class HaConfigDevicePage extends LitElement {
}
}
private _computeEntityName(
entity: EntityRegistryEntry,
devices: HomeAssistant["devices"]
) {
const device = devices[this.deviceId];
private _computeEntityName(entity: EntityRegistryEntry) {
const device = this.hass.devices[this.deviceId];
return (
computeEntityEntryName(entity, devices) ||
computeEntityEntryName(entity, this.hass.devices) ||
computeDeviceNameDisplay(device, this.hass)
);
}
@@ -1305,11 +1293,9 @@ export class HaConfigDevicePage extends LitElement {
private _createScene() {
const entities: SceneEntities = {};
this._entities(this.deviceId, this._entityReg, this.hass.devices).forEach(
(entity) => {
entities[entity.entity_id] = "";
}
);
this._entities(this.deviceId, this._entityReg).forEach((entity) => {
entities[entity.entity_id] = "";
});
showSceneEditor({
entities,
});
@@ -1374,11 +1360,9 @@ export class HaConfigDevicePage extends LitElement {
}
private _resetEntityIds = () => {
const entities = this._entities(
this.deviceId,
this._entityReg,
this.hass.devices
).map((e) => e.entity_id);
const entities = this._entities(this.deviceId, this._entityReg).map(
(e) => e.entity_id
);
regenerateEntityIds(this, this.hass, entities);
};
@@ -1470,11 +1454,7 @@ export class HaConfigDevicePage extends LitElement {
) {
return;
}
const entities = this._entities(
this.deviceId,
this._entityReg,
this.hass.devices
);
const entities = this._entities(this.deviceId, this._entityReg);
const updateProms = entities.map((entity) => {
const name = entity.name || entity.stateName;

View File

@@ -74,14 +74,19 @@ class HaConfigHardwareAll extends LitElement {
);
private _data = memoizeOne(
(hardware: HassioHardwareInfo): DataTableRowData[] =>
hardware.devices.map((device) => ({
...device,
id: device.dev_path,
attributes_string: Object.entries(device.attributes)
.map(([key, value]) => `${key}: ${value}`)
.join(" "),
}))
(showAdvanced: boolean, hardware: HassioHardwareInfo): DataTableRowData[] =>
hardware.devices
.filter(
(device) =>
showAdvanced || ["tty", "gpio", "input"].includes(device.subsystem)
)
.map((device) => ({
...device,
id: device.dev_path,
attributes_string: Object.entries(device.attributes)
.map(([key, value]) => `${key}: ${value}`)
.join(" "),
}))
);
protected firstUpdated(): void {
@@ -98,7 +103,12 @@ class HaConfigHardwareAll extends LitElement {
.tabs=${hardwareTabs(this.hass)}
clickable
.columns=${this._columns(this.hass.localize)}
.data=${this._hardware ? this._data(this._hardware) : []}
.data=${this._hardware
? this._data(
this.hass.userData?.showAdvanced || false,
this._hardware
)
: []}
.noDataText=${this._error ||
this.hass.localize("ui.panel.config.hardware.loading_system_data")}
@row-click=${this._handleRowClicked}

View File

@@ -250,7 +250,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
}
private _fillUrlPath(title: string) {
if (this._urlPathChanged || !title) {
if ((this.hass.userData?.showAdvanced && this._urlPathChanged) || !title) {
return;
}

View File

@@ -1,50 +1,17 @@
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeCssColor } from "../../../common/color/compute-color";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/entity/ha-entities-picker";
import "../../../components/ha-alert";
import "../../../components/ha-button";
import "../../../components/ha-dialog-footer";
import "../../../components/ha-dialog";
import "../../../components/ha-icon";
import "../../../components/ha-switch";
import type { HomeFrontendSystemData } from "../../../data/frontend";
import type { HassDialog } from "../../../dialogs/make-dialog-manager";
import {
getSummaryLabel,
HOME_SUMMARIES_ICONS,
type HomeSummary,
} from "../../lovelace/strategies/home/helpers/home-summaries";
import { haStyleDialog } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import type { EditHomeDialogParams } from "./show-dialog-edit-home";
interface SummaryInfo {
key: string;
icon: string;
color: string;
}
// Ordered to match dashboard rendering order
const SUMMARY_ITEMS: SummaryInfo[] = [
{ key: "light", icon: HOME_SUMMARIES_ICONS.light, color: "amber" },
{ key: "climate", icon: HOME_SUMMARIES_ICONS.climate, color: "deep-orange" },
{
key: "security",
icon: HOME_SUMMARIES_ICONS.security,
color: "blue-grey",
},
{
key: "media_players",
icon: HOME_SUMMARIES_ICONS.media_players,
color: "blue",
},
{ key: "weather", icon: "mdi:weather-partly-cloudy", color: "teal" },
{ key: "energy", icon: HOME_SUMMARIES_ICONS.energy, color: "amber" },
];
@customElement("dialog-edit-home")
export class DialogEditHome
extends LitElement
@@ -83,8 +50,6 @@ export class DialogEditHome
return nothing;
}
const hiddenSummaries = new Set(this._config?.hidden_summaries || []);
return html`
<ha-dialog
.hass=${this.hass}
@@ -114,33 +79,6 @@ export class DialogEditHome
@value-changed=${this._favoriteEntitiesChanged}
></ha-entities-picker>
<h3 class="section-header">
${this.hass.localize("ui.panel.home.editor.summaries")}
</h3>
<p class="section-description">
${this.hass.localize("ui.panel.home.editor.summaries_description")}
</p>
<div class="summary-toggles">
${SUMMARY_ITEMS.map((item) => {
const label = this._getSummaryLabel(item.key);
const color = computeCssColor(item.color);
return html`
<label class="summary-toggle">
<ha-icon
.icon=${item.icon}
style=${styleMap({ "--mdc-icon-size": "24px", color })}
></ha-icon>
<span class="summary-label">${label}</span>
<ha-switch
.checked=${!hiddenSummaries.has(item.key)}
.summary=${item.key}
@change=${this._summaryToggleChanged}
></ha-switch>
</label>
`;
})}
</div>
<ha-alert alert-type="info">
${this.hass.localize("ui.panel.home.editor.areas_hint", {
areas_page: html`<a
@@ -172,38 +110,6 @@ export class DialogEditHome
`;
}
private _getSummaryLabel(key: string): string {
if (key === "weather") {
return this.hass.localize(
"ui.panel.lovelace.strategy.home.summary_list.weather"
);
}
return getSummaryLabel(this.hass.localize, key as HomeSummary);
}
private _summaryToggleChanged(ev: Event): void {
const target = ev.target as HTMLElement & {
checked: boolean;
summary: string;
};
const summary = target.summary;
const checked = target.checked;
const hiddenSummaries = new Set(this._config?.hidden_summaries || []);
if (checked) {
hiddenSummaries.delete(summary);
} else {
hiddenSummaries.add(summary);
}
this._config = {
...this._config,
hidden_summaries:
hiddenSummaries.size > 0 ? [...hiddenSummaries] : undefined,
};
}
private _favoriteEntitiesChanged(ev: CustomEvent): void {
const entities = ev.detail.value as string[];
this._config = {
@@ -242,36 +148,6 @@ export class DialogEditHome
color: var(--secondary-text-color);
}
.section-header {
font-size: 16px;
font-weight: 500;
margin: var(--ha-space-6) 0 var(--ha-space-1) 0;
}
.section-description {
margin: 0 0 var(--ha-space-2) 0;
color: var(--secondary-text-color);
font-size: 14px;
}
.summary-toggles {
display: flex;
flex-direction: column;
}
.summary-toggle {
display: flex;
align-items: center;
gap: var(--ha-space-3);
padding: var(--ha-space-2) 0;
cursor: pointer;
}
.summary-label {
flex: 1;
font-size: 14px;
}
ha-entities-picker {
display: block;
}

View File

@@ -318,7 +318,6 @@ class PanelHome extends LitElement {
type: "home",
favorite_entities: this._config.favorite_entities,
home_panel: true,
hidden_summaries: this._config.hidden_summaries,
},
};

View File

@@ -187,15 +187,8 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard {
this._names = {};
this._entities.forEach((config) => {
const stateObj = this.hass!.states[config.entity];
if (stateObj) {
this._names[config.entity] =
this.hass!.formatEntityName(stateObj, config.name) || config.entity;
} else {
this._names[config.entity] =
(typeof config.name === "string" ? config.name : undefined) ||
this._metadata?.[config.entity]?.name ||
config.entity;
}
this._names[config.entity] =
this.hass!.formatEntityName(stateObj, config.name) || config.entity;
});
}

View File

@@ -247,7 +247,7 @@ class HUIRoot extends LitElement {
icon: mdiFileMultiple,
key: "ui.panel.lovelace.editor.menu.manage_resources",
overflowAction: this._handleManageResources,
visible: this._editMode,
visible: this._editMode && this.hass.userData?.showAdvanced,
overflow: true,
},
{

View File

@@ -17,7 +17,6 @@ export interface HomeDashboardStrategyConfig {
type: "home";
favorite_entities?: string[];
home_panel?: boolean;
hidden_summaries?: string[];
}
@customElement("home-dashboard-strategy")
@@ -95,7 +94,6 @@ export class HomeDashboardStrategy extends ReactiveElement {
type: "home-overview",
favorite_entities: config.favorite_entities,
home_panel: config.home_panel,
hidden_summaries: config.hidden_summaries,
} satisfies HomeOverviewViewStrategyConfig,
},
...areaViews,

View File

@@ -39,7 +39,6 @@ export interface HomeOverviewViewStrategyConfig {
type: "home-overview";
favorite_entities?: string[];
home_panel?: boolean;
hidden_summaries?: string[];
}
const computeAreaCard = (
@@ -255,8 +254,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
) ??
false);
const hiddenSummaries = new Set(config.hidden_summaries || []);
// Build summary cards (used in both mobile section and sidebar)
const summaryCards: LovelaceCardConfig[] = [
// Repairs card - only visible to admins, hides when empty
@@ -283,7 +280,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
hide_empty: true,
} satisfies DiscoveredDevicesCardConfig,
hasLights &&
!hiddenSummaries.has("light") &&
({
type: "home-summary",
summary: "light",
@@ -293,7 +289,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
},
} satisfies HomeSummaryCard),
hasClimate &&
!hiddenSummaries.has("climate") &&
({
type: "home-summary",
summary: "climate",
@@ -303,7 +298,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
},
} satisfies HomeSummaryCard),
hasSecurity &&
!hiddenSummaries.has("security") &&
({
type: "home-summary",
summary: "security",
@@ -313,7 +307,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
},
} satisfies HomeSummaryCard),
hasMediaPlayers &&
!hiddenSummaries.has("media_players") &&
({
type: "home-summary",
summary: "media_players",
@@ -323,7 +316,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
},
} satisfies HomeSummaryCard),
weatherEntity &&
!hiddenSummaries.has("weather") &&
({
type: "tile",
entity: weatherEntity,
@@ -333,7 +325,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
state_content: ["temperature", "state"],
} satisfies TileCardConfig),
hasEnergy &&
!hiddenSummaries.has("energy") &&
({
type: "home-summary",
summary: "energy",

View File

@@ -2462,9 +2462,7 @@
"favorite_entities_helper": "Display your favorite entities. Home Assistant will still suggest based on commonly used up to 8 slots.",
"save_failed": "Failed to save Overview page configuration",
"areas_hint": "You can rearrange your floors and areas in the order that best represents your house on the {areas_page}.",
"areas_page": "areas page",
"summaries": "Summaries",
"summaries_description": "Choose which summaries to show on your overview page."
"areas_page": "areas page"
},
"new_overview_dialog": {
"title": "Welcome to your new overview",
@@ -5041,7 +5039,7 @@
}
},
"event": {
"label": "Manual event received",
"label": "Manual event",
"event_type": "Event type",
"event_data": "Event data",
"context_users": "Limit to events triggered by",
@@ -5534,7 +5532,7 @@
}
},
"event": {
"label": "Fire manual event",
"label": "Manual event",
"event": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_type%]",
"event_data": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_data%]",
"description": {
@@ -9310,7 +9308,7 @@
"label_mode": "Label mode",
"maximum": "Maximum",
"manual": "Manual",
"manual_description": "Need to add a community card or just want to manually write the YAML?",
"manual_description": "Need to add a custom card or just want to manually write the YAML?",
"minimum": "Minimum",
"name": "Name",
"paste": "Paste from clipboard",
@@ -9333,7 +9331,7 @@
"suggested_cards": "Suggested cards",
"core_cards": "Core cards",
"energy_cards": "Energy cards",
"custom_cards": "Community cards",
"custom_cards": "Custom cards",
"round_temperature": "Round temperature",
"features": "Features",
"actions": "Actions",
@@ -9647,12 +9645,12 @@
},
"generic": {
"manual": "Manual",
"manual_description": "Need to add a community badge or just want to manually write the YAML?",
"manual_description": "Need to add a custom badge or just want to manually write the YAML?",
"paste": "Paste from clipboard",
"paste_description": "Paste a {type} badge from the clipboard",
"suggested_badges": "Suggested badges",
"other_badges": "Other badges",
"custom_badges": "Community badges"
"custom_badges": "Custom badges"
}
},
"entities": {

View File

@@ -7,7 +7,7 @@
"useDefineForClassFields": false,
// Modules
"module": "ESNext",
"moduleResolution": "bundler",
"moduleResolution": "node",
"resolveJsonModule": true,
// Babel handles transpiling and no need for declaration files
"noEmit": true,
@@ -130,35 +130,7 @@
],
"@formatjs/intl-relativetimeformat/polyfill-force": [
"./node_modules/@formatjs/intl-relativetimeformat/polyfill-force.js"
],
"@formatjs/intl-durationformat/src/types": [
"./node_modules/@formatjs/intl-durationformat/src/types.js"
],
"@formatjs/intl-pluralrules/locale-data/en": [
"./node_modules/@formatjs/intl-pluralrules/locale-data/en.js"
],
"@home-assistant/webawesome/dist/components/*": [
"./node_modules/@home-assistant/webawesome/dist/components/*"
],
"@home-assistant/webawesome/dist/events/*": [
"./node_modules/@home-assistant/webawesome/dist/events/*"
],
"@home-assistant/webawesome/dist/internal/*": [
"./node_modules/@home-assistant/webawesome/dist/internal/*"
],
"@lit-labs/virtualizer/virtualize": [
"./node_modules/@lit-labs/virtualizer/virtualize.js"
],
"@lit/reactive-element/reactive-controller": [
"./node_modules/@lit/reactive-element/reactive-controller.js"
],
"echarts/types/src/*": ["./node_modules/echarts/types/src/*.d.ts"],
"echarts/lib/*": ["./node_modules/echarts/lib/*"],
"home-assistant-js-websocket/dist/*": [
"./node_modules/home-assistant-js-websocket/dist/*"
],
"lit/directives/join": ["./node_modules/lit/directives/join.js"],
"lit/directives/ref": ["./node_modules/lit/directives/ref.js"]
]
}
}
}

View File

@@ -9002,7 +9002,7 @@ __metadata:
terser-webpack-plugin: "npm:5.4.0"
tinykeys: "npm:3.0.0"
ts-lit-plugin: "npm:2.0.2"
typescript: "npm:6.0.2"
typescript: "npm:5.9.3"
typescript-eslint: "npm:8.57.2"
vite-tsconfig-paths: "npm:6.1.1"
vitest: "npm:4.1.2"
@@ -13894,13 +13894,13 @@ __metadata:
languageName: node
linkType: hard
"typescript@npm:6.0.2":
version: 6.0.2
resolution: "typescript@npm:6.0.2"
"typescript@npm:5.9.3":
version: 5.9.3
resolution: "typescript@npm:5.9.3"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10/b9fc2fcee7ee8e5ca6f5138181964550531e18e2d20ecb71b802d4d495881e3444e0ef94cbb6e84eb2ba41e913f6feae3ca33cc722b32e6e6dfadb32d23b80e6
checksum: 10/c089d9d3da2729fd4ac517f9b0e0485914c4b3c26f80dc0cffcb5de1719a17951e92425d55db59515c1a7ddab65808466debb864d0d56dcf43f27007d0709594
languageName: node
linkType: hard
@@ -13914,13 +13914,13 @@ __metadata:
languageName: node
linkType: hard
"typescript@patch:typescript@npm%3A6.0.2#optional!builtin<compat/typescript>":
version: 6.0.2
resolution: "typescript@patch:typescript@npm%3A6.0.2#optional!builtin<compat/typescript>::version=6.0.2&hash=5786d5"
"typescript@patch:typescript@npm%3A5.9.3#optional!builtin<compat/typescript>":
version: 5.9.3
resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin<compat/typescript>::version=5.9.3&hash=5786d5"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10/e5501dfcf8c5b6b9a61f6fa53decc40187cebe3a2b7b2bd51c615007ad4cf6d58298461fef63294f6be9d5f2f33019b2a2e2bf02d9cb7d7f6ec94372bf24ffa2
checksum: 10/696e1b017bc2635f4e0c94eb4435357701008e2f272f553d06e35b494b8ddc60aa221145e286c28ace0c89ee32827a28c2040e3a69bdc108b1a5dc8fb40b72e3
languageName: node
linkType: hard