mirror of
https://github.com/home-assistant/frontend.git
synced 2026-03-03 05:47:54 +00:00
Compare commits
4 Commits
dev
...
strategy-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1d69eb94f | ||
|
|
7193102634 | ||
|
|
003511bc9c | ||
|
|
c7f583461c |
@@ -118,6 +118,8 @@ export class HaDataTable extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public clickable = false;
|
||||
|
||||
@property({ attribute: "has-fab", type: Boolean }) public hasFab = false;
|
||||
|
||||
/**
|
||||
* Add an extra row at the bottom of the data table
|
||||
* @type {TemplateResult}
|
||||
@@ -517,6 +519,7 @@ export class HaDataTable extends LitElement {
|
||||
this._filteredData,
|
||||
localize,
|
||||
this.appendRow,
|
||||
this.hasFab,
|
||||
this.groupColumn,
|
||||
this.groupOrder,
|
||||
this._collapsedGroups,
|
||||
@@ -713,13 +716,14 @@ export class HaDataTable extends LitElement {
|
||||
data: DataTableRowData[],
|
||||
localize: LocalizeFunc,
|
||||
appendRow,
|
||||
hasFab: boolean,
|
||||
groupColumn: string | undefined,
|
||||
groupOrder: string[] | undefined,
|
||||
collapsedGroups: string[],
|
||||
sortColumn: string | undefined,
|
||||
sortDirection: SortingDirection
|
||||
) => {
|
||||
if (appendRow || groupColumn) {
|
||||
if (appendRow || hasFab || groupColumn) {
|
||||
let items = [...data];
|
||||
|
||||
if (groupColumn) {
|
||||
@@ -809,11 +813,13 @@ export class HaDataTable extends LitElement {
|
||||
items.push({ append: true, selectable: false, content: appendRow });
|
||||
}
|
||||
|
||||
items.push({ empty: true });
|
||||
if (hasFab) {
|
||||
items.push({ empty: true });
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
return [...data, { empty: true }];
|
||||
return data;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -865,6 +871,7 @@ export class HaDataTable extends LitElement {
|
||||
this._filteredData,
|
||||
this.localizeFunc || this.hass.localize,
|
||||
this.appendRow,
|
||||
this.hasFab,
|
||||
this.groupColumn,
|
||||
this.groupOrder,
|
||||
this._collapsedGroups,
|
||||
@@ -1082,8 +1089,11 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
|
||||
.mdc-data-table__row.empty-row {
|
||||
height: var(
|
||||
--data-table-empty-row-height,
|
||||
height: max(
|
||||
var(
|
||||
--data-table-empty-row-height,
|
||||
var(--data-table-row-height, 52px)
|
||||
),
|
||||
var(--safe-area-inset-bottom, 0px)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,9 +84,6 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
@property({ type: Boolean, attribute: "disable-fullscreen" })
|
||||
public disableFullscreen = false;
|
||||
|
||||
@property({ type: Boolean, attribute: "in-dialog" })
|
||||
public inDialog = false;
|
||||
|
||||
@property({ type: Boolean, attribute: "has-toolbar" })
|
||||
public hasToolbar = true;
|
||||
|
||||
@@ -135,7 +132,6 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.classList.toggle("in-dialog", this.inDialog);
|
||||
// Force update on reconnection so editor is recreated
|
||||
if (this.hasUpdated) {
|
||||
this.requestUpdate();
|
||||
@@ -154,7 +150,6 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
fireEvent(this, "dialog-set-fullscreen", false);
|
||||
super.disconnectedCallback();
|
||||
this.removeEventListener("keydown", stopPropagation);
|
||||
this.removeEventListener("keydown", this._handleKeyDown);
|
||||
@@ -221,9 +216,6 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
if (changedProps.has("error")) {
|
||||
this.classList.toggle("error-state", this.error);
|
||||
}
|
||||
if (changedProps.has("inDialog")) {
|
||||
this.classList.toggle("in-dialog", this.inDialog);
|
||||
}
|
||||
if (changedProps.has("_isFullscreen")) {
|
||||
this.classList.toggle("fullscreen", this._isFullscreen);
|
||||
this._updateToolbarButtons();
|
||||
@@ -442,19 +434,10 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
private _updateFullscreenState(
|
||||
fullscreen: boolean = this._isFullscreen
|
||||
): boolean {
|
||||
const previousFullscreen = this._isFullscreen;
|
||||
|
||||
this.classList.toggle("in-dialog", this.inDialog);
|
||||
|
||||
// Update the current fullscreen state based on selected value. If fullscreen
|
||||
// is disabled, or we have no toolbar, ensure we are not in fullscreen mode.
|
||||
this._isFullscreen =
|
||||
fullscreen && !this.disableFullscreen && this.hasToolbar;
|
||||
|
||||
if (previousFullscreen !== this._isFullscreen) {
|
||||
fireEvent(this, "dialog-set-fullscreen", this._isFullscreen);
|
||||
}
|
||||
|
||||
// Return whether successfully in requested state
|
||||
return this._isFullscreen === fullscreen;
|
||||
}
|
||||
@@ -863,10 +846,10 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
|
||||
:host(.fullscreen) {
|
||||
position: fixed !important;
|
||||
top: calc(var(--header-height, 56px) + var(--ha-space-2)) !important;
|
||||
left: var(--ha-space-2) !important;
|
||||
right: var(--ha-space-2) !important;
|
||||
bottom: var(--ha-space-2) !important;
|
||||
top: calc(var(--header-height, 56px) + 8px) !important;
|
||||
left: 8px !important;
|
||||
right: 8px !important;
|
||||
bottom: 8px !important;
|
||||
z-index: 6;
|
||||
border-radius: var(--ha-border-radius-lg) !important;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3) !important;
|
||||
@@ -884,17 +867,6 @@ export class HaCodeEditor extends ReactiveElement {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
:host(.in-dialog.fullscreen) {
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
box-shadow: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
:host(.hasToolbar) .cm-editor {
|
||||
padding-top: var(--code-editor-toolbar-height);
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ import {
|
||||
state,
|
||||
} from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import type { HASSDomEvent } from "../common/dom/fire_event";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { withViewTransition } from "../common/util/view-transition";
|
||||
import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin";
|
||||
import { haStyleScrollbar } from "../resources/styles";
|
||||
import type { HomeAssistant } from "../types";
|
||||
@@ -129,14 +127,6 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||
|
||||
private _escapePressed = false;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.addEventListener(
|
||||
"dialog-set-fullscreen",
|
||||
this._handleFullscreenChanged as EventListener
|
||||
);
|
||||
}
|
||||
|
||||
protected get scrollableElement(): HTMLElement | null {
|
||||
return this.bodyContainer;
|
||||
}
|
||||
@@ -243,36 +233,15 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||
private _handleAfterHide = (ev: DialogHideEvent) => {
|
||||
if (ev.eventPhase === Event.AT_TARGET) {
|
||||
this._open = false;
|
||||
this._setFullscreen(false);
|
||||
fireEvent(this, "closed");
|
||||
}
|
||||
};
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
this.removeEventListener(
|
||||
"dialog-set-fullscreen",
|
||||
this._handleFullscreenChanged as EventListener
|
||||
);
|
||||
this._setFullscreen(false);
|
||||
super.disconnectedCallback();
|
||||
this._open = false;
|
||||
}
|
||||
|
||||
private _handleFullscreenChanged(ev: HASSDomEvent<boolean>): void {
|
||||
if (!this._open) {
|
||||
this._setFullscreen(ev.detail);
|
||||
return;
|
||||
}
|
||||
|
||||
withViewTransition(() => {
|
||||
this._setFullscreen(ev.detail);
|
||||
});
|
||||
}
|
||||
|
||||
private _setFullscreen(fullscreen: boolean): void {
|
||||
this.toggleAttribute("fullscreen", fullscreen);
|
||||
}
|
||||
|
||||
@eventOptions({ passive: true })
|
||||
private _handleBodyScroll(ev: Event) {
|
||||
this._bodyScrolled = (ev.target as HTMLDivElement).scrollTop > 0;
|
||||
@@ -338,27 +307,10 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
|
||||
--width: min(var(--ha-dialog-width-lg, 1024px), var(--full-width));
|
||||
}
|
||||
|
||||
:host([width="full"]) wa-dialog,
|
||||
:host([fullscreen]) wa-dialog {
|
||||
:host([width="full"]) wa-dialog {
|
||||
--width: var(--full-width);
|
||||
}
|
||||
|
||||
:host([fullscreen]) wa-dialog::part(dialog) {
|
||||
min-height: var(--safe-height);
|
||||
max-height: var(--safe-height);
|
||||
margin-top: 0;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
:host([fullscreen]) .content-wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:host([fullscreen]) .body {
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
wa-dialog::part(dialog) {
|
||||
-webkit-backdrop-filter: var(
|
||||
--ha-dialog-surface-backdrop-filter,
|
||||
@@ -519,7 +471,6 @@ declare global {
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"dialog-set-fullscreen": boolean;
|
||||
opened: undefined;
|
||||
"after-show": undefined;
|
||||
closed: undefined;
|
||||
|
||||
@@ -47,9 +47,6 @@ export class HaYamlEditor extends LitElement {
|
||||
@property({ type: Boolean, attribute: "disable-fullscreen" })
|
||||
public disableFullscreen = false;
|
||||
|
||||
@property({ type: Boolean, attribute: "in-dialog" })
|
||||
public inDialog = false;
|
||||
|
||||
@property({ type: Boolean }) public required = false;
|
||||
|
||||
@property({ attribute: "copy-clipboard", type: Boolean })
|
||||
@@ -104,13 +101,6 @@ export class HaYamlEditor extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
public disableCodeEditorFullscreen(): void {
|
||||
this.disableFullscreen = true;
|
||||
if (this._codeEditor) {
|
||||
this._codeEditor.disableFullscreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (this._yaml === undefined) {
|
||||
return nothing;
|
||||
@@ -124,7 +114,6 @@ export class HaYamlEditor extends LitElement {
|
||||
.value=${this._yaml}
|
||||
.readOnly=${this.readOnly}
|
||||
.disableFullscreen=${this.disableFullscreen}
|
||||
.inDialog=${this.inDialog}
|
||||
mode="yaml"
|
||||
autocomplete-entities
|
||||
autocomplete-icons
|
||||
|
||||
@@ -61,7 +61,6 @@ class HaMoreInfoDetails extends LitElement {
|
||||
.value=${yamlData}
|
||||
read-only
|
||||
auto-update
|
||||
in-dialog
|
||||
></ha-yaml-editor>`
|
||||
: html`
|
||||
<section class="section">
|
||||
|
||||
@@ -119,8 +119,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
|
||||
@query(".content") private _contentElement?: HTMLDivElement;
|
||||
|
||||
@query("ha-adaptive-dialog") private _dialogElement?: HTMLElement;
|
||||
|
||||
@state() private _entityId?: string | null;
|
||||
|
||||
@state() private _data?: Record<string, any>;
|
||||
@@ -179,10 +177,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
const dialog = this._dialogElement?.shadowRoot?.querySelector("ha-dialog");
|
||||
if (dialog) {
|
||||
fireEvent(dialog as HTMLElement, "dialog-set-fullscreen", false);
|
||||
}
|
||||
this._open = false;
|
||||
}
|
||||
|
||||
@@ -260,11 +254,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
|
||||
private _goBack() {
|
||||
if (this._childView) {
|
||||
const dialog =
|
||||
this._dialogElement?.shadowRoot?.querySelector("ha-dialog");
|
||||
if (dialog) {
|
||||
fireEvent(dialog as HTMLElement, "dialog-set-fullscreen", false);
|
||||
}
|
||||
this._childView = undefined;
|
||||
this._detailsYamlMode = false;
|
||||
return;
|
||||
@@ -331,10 +320,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _toggleDetailsYamlMode() {
|
||||
const dialog = this._dialogElement?.shadowRoot?.querySelector("ha-dialog");
|
||||
if (dialog) {
|
||||
fireEvent(dialog as HTMLElement, "dialog-set-fullscreen", false);
|
||||
}
|
||||
this._detailsYamlMode = !this._detailsYamlMode;
|
||||
}
|
||||
|
||||
@@ -764,21 +749,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
const previousChildView = changedProps.get("_childView") as
|
||||
| ChildView
|
||||
| undefined;
|
||||
|
||||
if (
|
||||
previousChildView?.viewTag === "ha-more-info-details" &&
|
||||
this._childView?.viewTag !== "ha-more-info-details"
|
||||
) {
|
||||
const dialog =
|
||||
this._dialogElement?.shadowRoot?.querySelector("ha-dialog");
|
||||
if (dialog) {
|
||||
fireEvent(dialog as HTMLElement, "dialog-set-fullscreen", false);
|
||||
}
|
||||
}
|
||||
|
||||
if (changedProps.has("_currView")) {
|
||||
this._childView = undefined;
|
||||
this._infoEditMode = false;
|
||||
|
||||
@@ -12,11 +12,10 @@ import {
|
||||
mdiUnfoldLessHorizontal,
|
||||
mdiUnfoldMoreHorizontal,
|
||||
} from "@mdi/js";
|
||||
import type { TemplateResult, PropertyValues } from "lit";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { canShowPage } from "../common/config/can_show_page";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import "../components/chips/ha-assist-chip";
|
||||
@@ -84,15 +83,7 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
* Do we need to add padding for a fab.
|
||||
* @type {Boolean}
|
||||
*/
|
||||
@property({ attribute: "has-fab", type: Boolean, reflect: true })
|
||||
public hasFab = false;
|
||||
|
||||
/**
|
||||
* Show tabs on top or at bottom (narrow) of the page.
|
||||
* @type {Boolean}
|
||||
*/
|
||||
@property({ attribute: "show-tabs", type: Boolean, reflect: true })
|
||||
public showTabs = false;
|
||||
@property({ attribute: "has-fab", type: Boolean }) public hasFab = false;
|
||||
|
||||
/**
|
||||
* Add an extra row at the bottom of the data table
|
||||
@@ -209,19 +200,7 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
this._dataTable.clearSelection();
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues) {
|
||||
if (
|
||||
changedProperties.has("tabs") ||
|
||||
(changedProperties.has("hass") &&
|
||||
(this.hass?.config.components !==
|
||||
changedProperties.get("hass")?.config.components ||
|
||||
this.hass?.userData?.showAdvanced !==
|
||||
changedProperties.get("hass")?.userData?.showAdvanced))
|
||||
) {
|
||||
this.showTabs =
|
||||
this.tabs.filter((page) => canShowPage(this.hass, page)).length > 1;
|
||||
}
|
||||
|
||||
protected willUpdate() {
|
||||
if (this.hasUpdated) {
|
||||
return;
|
||||
}
|
||||
@@ -512,6 +491,7 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
.noDataText=${this.noDataText}
|
||||
.filter=${this.filter}
|
||||
.selectable=${this._selectMode}
|
||||
.hasFab=${this.hasFab}
|
||||
.id=${this.id}
|
||||
.clickable=${this.clickable}
|
||||
.appendRow=${this.appendRow}
|
||||
@@ -733,7 +713,6 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
--data-table-border-width: 0;
|
||||
--data-table-empty-row-height: var(--safe-area-inset-bottom, 0px);
|
||||
}
|
||||
:host(:not([narrow])) ha-data-table,
|
||||
.pane {
|
||||
@@ -746,23 +725,6 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
|
||||
);
|
||||
display: block;
|
||||
}
|
||||
/* Last content row should keep the same padding above the fab as the fab
|
||||
has to the bottom (16px standard fab bottom padding) + the safe-area inset. */
|
||||
:host([has-fab]) ha-data-table {
|
||||
--data-table-empty-row-height: calc(
|
||||
48px + 16px * 2 + var(--safe-area-inset-bottom, 0px)
|
||||
);
|
||||
}
|
||||
/* In narrow view with tabs shown at the bottom, the tab bar already
|
||||
accounts for safe-area-inset-bottom. No extra empty-row height is needed. */
|
||||
:host([narrow][show-tabs]:not([has-fab])) ha-data-table {
|
||||
--data-table-empty-row-height: 0px;
|
||||
}
|
||||
/* Reserve space for fab + doubled narrow-mode bottom padding (28px * 2)
|
||||
when using narrow layout with bottom tabs. */
|
||||
:host([narrow][show-tabs][has-fab]) ha-data-table {
|
||||
--data-table-empty-row-height: calc(48px + 28px * 2);
|
||||
}
|
||||
|
||||
.pane-content {
|
||||
height: calc(
|
||||
|
||||
@@ -37,7 +37,7 @@ export interface PageNavigation {
|
||||
}
|
||||
|
||||
@customElement("hass-tabs-subpage")
|
||||
export class HassTabsSubpage extends LitElement {
|
||||
class HassTabsSubpage extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public localizeFunc?: LocalizeFunc;
|
||||
@@ -65,14 +65,6 @@ export class HassTabsSubpage extends LitElement {
|
||||
*/
|
||||
@property({ type: Boolean, attribute: "has-fab" }) public hasFab = false;
|
||||
|
||||
/**
|
||||
* Whether tabs are shown (2 or more tabs visible).
|
||||
* When both, show-tabs and narrow are true, tabs are shown as bottom bar.
|
||||
* @type {Boolean}
|
||||
*/
|
||||
@property({ type: Boolean, attribute: "show-tabs", reflect: true })
|
||||
public showTabs = false;
|
||||
|
||||
@state() private _activeTab?: PageNavigation;
|
||||
|
||||
// @ts-ignore
|
||||
@@ -91,7 +83,6 @@ export class HassTabsSubpage extends LitElement {
|
||||
const shownTabs = tabs.filter((page) => canShowPage(this.hass, page));
|
||||
|
||||
if (shownTabs.length < 2) {
|
||||
this.showTabs = false;
|
||||
if (shownTabs.length === 1) {
|
||||
const page = shownTabs[0];
|
||||
return [
|
||||
@@ -101,7 +92,6 @@ export class HassTabsSubpage extends LitElement {
|
||||
return [""];
|
||||
}
|
||||
|
||||
this.showTabs = true;
|
||||
return shownTabs.map(
|
||||
(page) => html`
|
||||
<a href=${page.path} @click=${this._tabClicked}>
|
||||
@@ -145,6 +135,7 @@ export class HassTabsSubpage extends LitElement {
|
||||
this.narrow,
|
||||
this.localizeFunc || this.hass.localize
|
||||
);
|
||||
const showTabs = tabs.length > 1;
|
||||
return html`
|
||||
<div class="toolbar ${classMap({ narrow: this.narrow })}">
|
||||
<slot name="toolbar">
|
||||
@@ -169,12 +160,12 @@ export class HassTabsSubpage extends LitElement {
|
||||
@click=${this._backTapped}
|
||||
></ha-icon-button-arrow-prev>
|
||||
`}
|
||||
${this.narrow || !this.showTabs
|
||||
${this.narrow || !showTabs
|
||||
? html`<div class="main-title">
|
||||
<slot name="header">${!this.showTabs ? tabs[0] : ""}</slot>
|
||||
<slot name="header">${!showTabs ? tabs[0] : ""}</slot>
|
||||
</div>`
|
||||
: ""}
|
||||
${this.showTabs && !this.narrow
|
||||
${showTabs && !this.narrow
|
||||
? html`<div id="tabbar">${tabs}</div>`
|
||||
: ""}
|
||||
<div id="toolbar-icon">
|
||||
@@ -182,11 +173,13 @@ export class HassTabsSubpage extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
${this.showTabs && this.narrow
|
||||
${showTabs && this.narrow
|
||||
? html`<div id="tabbar" class="bottom-bar">${tabs}</div>`
|
||||
: ""}
|
||||
</div>
|
||||
<div class="container">
|
||||
<div
|
||||
class=${classMap({ container: true, tabs: showTabs && this.narrow })}
|
||||
>
|
||||
${this.pane
|
||||
? html`<div class="pane">
|
||||
<div class="shadow-container"></div>
|
||||
@@ -195,12 +188,15 @@ export class HassTabsSubpage extends LitElement {
|
||||
</div>
|
||||
</div>`
|
||||
: nothing}
|
||||
<div class="content ha-scrollbar" @scroll=${this._saveScrollPos}>
|
||||
<div
|
||||
class="content ha-scrollbar ${classMap({ tabs: showTabs })}"
|
||||
@scroll=${this._saveScrollPos}
|
||||
>
|
||||
<slot></slot>
|
||||
${this.hasFab ? html`<div class="fab-bottom-space"></div>` : nothing}
|
||||
</div>
|
||||
</div>
|
||||
<div id="fab">
|
||||
<div id="fab" class=${classMap({ tabs: showTabs })}>
|
||||
<slot name="fab"></slot>
|
||||
</div>
|
||||
`;
|
||||
@@ -377,7 +373,7 @@ export class HassTabsSubpage extends LitElement {
|
||||
margin-left: var(--safe-area-inset-left);
|
||||
margin-inline-start: var(--safe-area-inset-left);
|
||||
}
|
||||
:host([narrow][show-tabs]) .content {
|
||||
:host([narrow]) .content.tabs {
|
||||
/* Bottom bar reuses header height */
|
||||
margin-bottom: calc(
|
||||
var(--header-height, 0px) + var(--safe-area-inset-bottom, 0px)
|
||||
@@ -388,7 +384,7 @@ export class HassTabsSubpage extends LitElement {
|
||||
height: calc(64px + var(--safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
:host([narrow][show-tabs]) .content .fab-bottom-space {
|
||||
:host([narrow]) .content.tabs .fab-bottom-space {
|
||||
height: calc(80px + var(--safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
@@ -404,7 +400,7 @@ export class HassTabsSubpage extends LitElement {
|
||||
justify-content: flex-end;
|
||||
gap: var(--ha-space-2);
|
||||
}
|
||||
:host([narrow][show-tabs]) #fab {
|
||||
:host([narrow]) #fab.tabs {
|
||||
bottom: calc(84px + var(--safe-area-inset-bottom, 0px));
|
||||
}
|
||||
#fab[is-wide] {
|
||||
|
||||
@@ -2,10 +2,10 @@ import type { LitElement, PropertyValues } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import { computeLocalize } from "../common/translations/localize";
|
||||
import { computeDirectionStyles } from "../common/util/compute_rtl";
|
||||
import { translationMetadata } from "../resources/translations-metadata";
|
||||
import type { Constructor, Resources } from "../types";
|
||||
import { getLocalLanguage, getTranslation } from "../util/common-translation";
|
||||
import { translationMetadata } from "../resources/translations-metadata";
|
||||
import { computeDirectionStyles } from "../common/util/compute_rtl";
|
||||
|
||||
const empty = () => "";
|
||||
|
||||
@@ -28,16 +28,16 @@ export const litLocalizeLiteMixin = <T extends Constructor<LitElement>>(
|
||||
this._initializeLocalizeLite();
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
computeDirectionStyles(
|
||||
translationMetadata.translations[this.language!].isRTL,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues) {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
if (!this.updated || changedProperties.has("language")) {
|
||||
computeDirectionStyles(
|
||||
translationMetadata.translations[this.language!].isRTL,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
if (changedProperties.get("language")) {
|
||||
this._resources = undefined;
|
||||
this._initializeLocalizeLite();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import type { LocalizeKeys } from "../../common/translations/localize";
|
||||
import "../../components/ha-alert";
|
||||
@@ -10,9 +11,13 @@ import "../../components/ha-top-app-bar-fixed";
|
||||
import type { EnergyPreferences } from "../../data/energy";
|
||||
import { getEnergyDataCollection } from "../../data/energy";
|
||||
import type { LovelaceConfig } from "../../data/lovelace/config/types";
|
||||
import type { LovelaceViewConfig } from "../../data/lovelace/config/view";
|
||||
import {
|
||||
isStrategyView,
|
||||
type LovelaceViewConfig,
|
||||
} from "../../data/lovelace/config/view";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant, PanelInfo } from "../../types";
|
||||
import "../lovelace/components/hui-energy-period-selector";
|
||||
import "../lovelace/hui-root";
|
||||
import type { Lovelace } from "../lovelace/types";
|
||||
import "../lovelace/views/hui-view";
|
||||
@@ -32,6 +37,7 @@ const OVERVIEW_VIEW = {
|
||||
strategy: {
|
||||
type: "energy-overview",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
show_period_selector: true,
|
||||
},
|
||||
} as LovelaceViewConfig;
|
||||
|
||||
@@ -40,6 +46,7 @@ const ENERGY_VIEW = {
|
||||
strategy: {
|
||||
type: "energy",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
show_period_selector: true,
|
||||
},
|
||||
} as LovelaceViewConfig;
|
||||
|
||||
@@ -48,6 +55,7 @@ const WATER_VIEW = {
|
||||
strategy: {
|
||||
type: "water",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
show_period_selector: true,
|
||||
},
|
||||
} as LovelaceViewConfig;
|
||||
|
||||
@@ -56,6 +64,7 @@ const GAS_VIEW = {
|
||||
strategy: {
|
||||
type: "gas",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
show_period_selector: true,
|
||||
},
|
||||
} as LovelaceViewConfig;
|
||||
|
||||
@@ -201,6 +210,16 @@ class PanelEnergy extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const routePath = this.route?.path?.split("/")[1] || "";
|
||||
const currentView = this._lovelace.config.views.find(
|
||||
(view) => view.path === routePath
|
||||
);
|
||||
|
||||
const showEnergySelector =
|
||||
currentView &&
|
||||
isStrategyView(currentView) &&
|
||||
currentView.strategy?.show_period_selector;
|
||||
|
||||
return html`
|
||||
<hui-root
|
||||
.hass=${this.hass}
|
||||
@@ -211,8 +230,22 @@ class PanelEnergy extends LitElement {
|
||||
.backButton=${this._searchParms.has("historyBack")}
|
||||
.backPath=${this._searchParms.get("backPath") || "/"}
|
||||
@reload-energy-panel=${this._reloadConfig}
|
||||
class=${classMap({ "has-period-selector": showEnergySelector })}
|
||||
>
|
||||
</hui-root>
|
||||
${showEnergySelector
|
||||
? html`
|
||||
<ha-card class="period-selector">
|
||||
<hui-energy-period-selector
|
||||
.hass=${this.hass}
|
||||
.collectionKey=${DEFAULT_ENERGY_COLLECTION_KEY}
|
||||
opening-direction="right"
|
||||
vertical-opening-direction="up"
|
||||
fixed
|
||||
></hui-energy-period-selector>
|
||||
</ha-card>
|
||||
`
|
||||
: nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -323,6 +356,50 @@ class PanelEnergy extends LitElement {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
hui-root.has-period-selector {
|
||||
--view-container-padding-bottom: var(--ha-space-18);
|
||||
}
|
||||
.period-selector {
|
||||
position: fixed;
|
||||
z-index: 4;
|
||||
bottom: max(var(--ha-space-4), var(--safe-area-inset-bottom, 0px));
|
||||
left: max(
|
||||
var(--mdc-drawer-width, 0px),
|
||||
var(--safe-area-inset-left, 0px)
|
||||
);
|
||||
right: var(--safe-area-inset-right, 0);
|
||||
inset-inline-start: max(
|
||||
var(--mdc-drawer-width, 0px),
|
||||
var(--safe-area-inset-left, 0px)
|
||||
);
|
||||
inset-inline-end: var(--safe-area-inset-right, 0);
|
||||
transition:
|
||||
left var(--ha-animation-duration-normal) ease,
|
||||
right var(--ha-animation-duration-normal) ease,
|
||||
inset-inline-start var(--ha-animation-duration-normal) ease,
|
||||
inset-inline-end var(--ha-animation-duration-normal) ease;
|
||||
margin: 0 auto;
|
||||
max-width: calc(min(470px, 100% - var(--ha-space-4)));
|
||||
box-sizing: border-box;
|
||||
padding-left: var(--ha-space-2);
|
||||
padding-right: 0;
|
||||
padding-inline-start: var(--ha-space-4);
|
||||
padding-inline-end: 0;
|
||||
--ha-card-box-shadow:
|
||||
0px 3px 5px -1px rgba(0, 0, 0, 0.2),
|
||||
0px 6px 10px 0px rgba(0, 0, 0, 0.14),
|
||||
0px 1px 18px 0px rgba(0, 0, 0, 0.12);
|
||||
--ha-card-border-color: var(--divider-color);
|
||||
--ha-card-border-width: var(--ha-card-border-width, 1px);
|
||||
}
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
hui-root.has-period-selector {
|
||||
--view-container-padding-bottom: var(--ha-space-14);
|
||||
}
|
||||
.period-selector {
|
||||
bottom: max(var(--ha-space-2), var(--safe-area-inset-bottom, 0px));
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -13,23 +13,16 @@ export class EnergyOverviewViewStrategy extends ReactiveElement {
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const view: LovelaceViewConfig = {
|
||||
type: "sections",
|
||||
sections: [],
|
||||
dense_section_placement: true,
|
||||
max_columns: 3,
|
||||
footer: {
|
||||
column_span: 1.1,
|
||||
card: {
|
||||
type: "energy-date-selection",
|
||||
collection_key: collectionKey,
|
||||
},
|
||||
},
|
||||
max_columns: 2,
|
||||
};
|
||||
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const energyCollection = getEnergyDataCollection(hass, {
|
||||
key: collectionKey,
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import type { GridSourceTypeEnergyPreference } from "../../../data/energy";
|
||||
import { getEnergyDataCollection } from "../../../data/energy";
|
||||
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy";
|
||||
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
@@ -15,22 +14,11 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const view: LovelaceViewConfig = { cards: [] };
|
||||
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const view: LovelaceViewConfig = {
|
||||
type: "sections",
|
||||
max_columns: 3,
|
||||
sections: [],
|
||||
footer: {
|
||||
column_span: 1.1,
|
||||
card: {
|
||||
type: "energy-date-selection",
|
||||
collection_key: collectionKey,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const energyCollection = getEnergyDataCollection(hass, {
|
||||
key: collectionKey,
|
||||
});
|
||||
@@ -48,6 +36,8 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
return view;
|
||||
}
|
||||
|
||||
view.type = "sidebar";
|
||||
|
||||
const hasGrid = prefs.energy_sources.find(
|
||||
(source): source is GridSourceTypeEnergyPreference =>
|
||||
source.type === "grid" &&
|
||||
@@ -60,95 +50,83 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
const hasBattery = prefs.energy_sources.some(
|
||||
(source) => source.type === "battery"
|
||||
);
|
||||
|
||||
const mainCards: LovelaceCardConfig[] = [];
|
||||
const gaugeCards: LovelaceCardConfig[] = [];
|
||||
|
||||
// Only include if we have a grid source & return.
|
||||
if (hasReturn) {
|
||||
const card = {
|
||||
type: "energy-grid-neutrality-gauge",
|
||||
collection_key: collectionKey,
|
||||
};
|
||||
gaugeCards.push(card);
|
||||
}
|
||||
|
||||
// Only include if we have a solar source.
|
||||
if (hasSolar) {
|
||||
if (hasReturn) {
|
||||
const card = {
|
||||
type: "energy-solar-consumed-gauge",
|
||||
collection_key: collectionKey,
|
||||
};
|
||||
gaugeCards.push(card);
|
||||
}
|
||||
if (hasGrid) {
|
||||
const card = {
|
||||
type: "energy-self-sufficiency-gauge",
|
||||
collection_key: collectionKey,
|
||||
};
|
||||
gaugeCards.push(card);
|
||||
}
|
||||
}
|
||||
|
||||
// Only include if we have a grid
|
||||
if (hasGrid) {
|
||||
const card = {
|
||||
type: "energy-carbon-consumed-gauge",
|
||||
collection_key: collectionKey,
|
||||
};
|
||||
gaugeCards.push(card);
|
||||
}
|
||||
|
||||
if (gaugeCards.length) {
|
||||
view.sections!.push({
|
||||
type: "grid",
|
||||
column_span: 3,
|
||||
cards:
|
||||
gaugeCards.length === 1
|
||||
? [gaugeCards[0]]
|
||||
: gaugeCards.map((card) => ({
|
||||
...card,
|
||||
grid_options: { columns: 6 },
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
mainCards.push({
|
||||
view.cards!.push({
|
||||
type: "energy-compare",
|
||||
collection_key: collectionKey,
|
||||
grid_options: { columns: 36 },
|
||||
});
|
||||
|
||||
// Only include if we have a grid or battery.
|
||||
if (hasGrid || hasBattery) {
|
||||
mainCards.push({
|
||||
view.cards!.push({
|
||||
title: hass.localize("ui.panel.energy.cards.energy_usage_graph_title"),
|
||||
type: "energy-usage-graph",
|
||||
collection_key: collectionKey,
|
||||
grid_options: { columns: 36 },
|
||||
});
|
||||
}
|
||||
|
||||
// Only include if we have a solar source.
|
||||
if (hasSolar) {
|
||||
mainCards.push({
|
||||
view.cards!.push({
|
||||
title: hass.localize("ui.panel.energy.cards.energy_solar_graph_title"),
|
||||
type: "energy-solar-graph",
|
||||
collection_key: collectionKey,
|
||||
grid_options: { columns: 36 },
|
||||
});
|
||||
}
|
||||
|
||||
// Only include if we have a grid or battery.
|
||||
if (hasGrid || hasBattery) {
|
||||
view.cards!.push({
|
||||
title: hass.localize("ui.panel.energy.cards.energy_distribution_title"),
|
||||
type: "energy-distribution",
|
||||
view_layout: { position: "sidebar" },
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasGrid || hasSolar || hasBattery) {
|
||||
mainCards.push({
|
||||
view.cards!.push({
|
||||
title: hass.localize(
|
||||
"ui.panel.energy.cards.energy_sources_table_title"
|
||||
),
|
||||
type: "energy-sources-table",
|
||||
collection_key: collectionKey,
|
||||
types: ["grid", "solar", "battery"],
|
||||
grid_options: { columns: 36 },
|
||||
});
|
||||
}
|
||||
|
||||
// Only include if we have a grid source & return.
|
||||
if (hasReturn) {
|
||||
view.cards!.push({
|
||||
type: "energy-grid-neutrality-gauge",
|
||||
view_layout: { position: "sidebar" },
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
}
|
||||
|
||||
// Only include if we have a solar source.
|
||||
if (hasSolar) {
|
||||
if (hasReturn) {
|
||||
view.cards!.push({
|
||||
type: "energy-solar-consumed-gauge",
|
||||
view_layout: { position: "sidebar" },
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
}
|
||||
if (hasGrid) {
|
||||
view.cards!.push({
|
||||
type: "energy-self-sufficiency-gauge",
|
||||
view_layout: { position: "sidebar" },
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Only include if we have a grid
|
||||
if (hasGrid) {
|
||||
view.cards!.push({
|
||||
type: "energy-carbon-consumed-gauge",
|
||||
view_layout: { position: "sidebar" },
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -159,38 +137,29 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
hass,
|
||||
(d) => d.stat_consumption
|
||||
);
|
||||
mainCards.push({
|
||||
view.cards!.push({
|
||||
title: hass.localize(
|
||||
"ui.panel.energy.cards.energy_devices_detail_graph_title"
|
||||
),
|
||||
type: "energy-devices-detail-graph",
|
||||
collection_key: collectionKey,
|
||||
grid_options: { columns: 36 },
|
||||
});
|
||||
mainCards.push({
|
||||
view.cards!.push({
|
||||
title: hass.localize(
|
||||
"ui.panel.energy.cards.energy_devices_graph_title"
|
||||
),
|
||||
type: "energy-devices-graph",
|
||||
collection_key: collectionKey,
|
||||
grid_options: { columns: 36 },
|
||||
});
|
||||
mainCards.push({
|
||||
view.cards!.push({
|
||||
title: hass.localize("ui.panel.energy.cards.energy_sankey_title"),
|
||||
type: "energy-sankey",
|
||||
collection_key: collectionKey,
|
||||
group_by_floor: showFloorsAndAreas,
|
||||
group_by_area: showFloorsAndAreas,
|
||||
grid_options: { columns: 36 },
|
||||
});
|
||||
}
|
||||
|
||||
view.sections!.push({
|
||||
type: "grid",
|
||||
column_span: 3,
|
||||
cards: mainCards,
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,22 +13,14 @@ export class GasViewStrategy extends ReactiveElement {
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const view: LovelaceViewConfig = {
|
||||
type: "sections",
|
||||
max_columns: 3,
|
||||
sections: [{ type: "grid", cards: [], column_span: 3 }],
|
||||
footer: {
|
||||
column_span: 1.1,
|
||||
card: {
|
||||
type: "energy-date-selection",
|
||||
collection_key: collectionKey,
|
||||
},
|
||||
},
|
||||
sections: [{ type: "grid", cards: [] }],
|
||||
};
|
||||
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const energyCollection = getEnergyDataCollection(hass, {
|
||||
key: collectionKey,
|
||||
});
|
||||
@@ -57,9 +49,6 @@ export class GasViewStrategy extends ReactiveElement {
|
||||
title: hass.localize("ui.panel.energy.cards.energy_gas_graph_title"),
|
||||
type: "energy-gas-graph",
|
||||
collection_key: collectionKey,
|
||||
grid_options: {
|
||||
columns: 24,
|
||||
},
|
||||
});
|
||||
|
||||
section.cards!.push({
|
||||
@@ -67,9 +56,6 @@ export class GasViewStrategy extends ReactiveElement {
|
||||
type: "energy-sources-table",
|
||||
collection_key: collectionKey,
|
||||
types: ["gas"],
|
||||
grid_options: {
|
||||
columns: 12,
|
||||
},
|
||||
});
|
||||
|
||||
return view;
|
||||
|
||||
@@ -14,22 +14,14 @@ export class WaterViewStrategy extends ReactiveElement {
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const view: LovelaceViewConfig = {
|
||||
type: "sections",
|
||||
max_columns: 3,
|
||||
sections: [{ type: "grid", cards: [], column_span: 3 }],
|
||||
footer: {
|
||||
column_span: 1.1,
|
||||
card: {
|
||||
type: "energy-date-selection",
|
||||
collection_key: collectionKey,
|
||||
},
|
||||
},
|
||||
sections: [{ type: "grid", cards: [] }],
|
||||
};
|
||||
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const energyCollection = getEnergyDataCollection(hass, {
|
||||
key: collectionKey,
|
||||
});
|
||||
@@ -60,9 +52,6 @@ export class WaterViewStrategy extends ReactiveElement {
|
||||
title: hass.localize("ui.panel.energy.cards.energy_water_graph_title"),
|
||||
type: "energy-water-graph",
|
||||
collection_key: collectionKey,
|
||||
grid_options: {
|
||||
columns: 24,
|
||||
},
|
||||
});
|
||||
section.cards!.push({
|
||||
title: hass.localize(
|
||||
@@ -71,9 +60,6 @@ export class WaterViewStrategy extends ReactiveElement {
|
||||
type: "energy-sources-table",
|
||||
collection_key: collectionKey,
|
||||
types: ["water"],
|
||||
grid_options: {
|
||||
columns: 12,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,9 +76,6 @@ export class WaterViewStrategy extends ReactiveElement {
|
||||
collection_key: collectionKey,
|
||||
group_by_floor: showFloorsAndAreas,
|
||||
group_by_area: showFloorsAndAreas,
|
||||
grid_options: {
|
||||
columns: 24,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -131,10 +131,9 @@ export class HuiDiscoveredDevicesCard
|
||||
}
|
||||
|
||||
// Update visibility based on admin status and discovered devices count
|
||||
const shouldBeHidden = Boolean(
|
||||
const shouldBeHidden =
|
||||
!this.hass.user?.is_admin ||
|
||||
(this._config.hide_empty && this._discoveredFlows.length === 0)
|
||||
);
|
||||
(this._config.hide_empty && this._discoveredFlows.length === 0);
|
||||
|
||||
if (shouldBeHidden !== this.hidden) {
|
||||
this.style.display = shouldBeHidden ? "none" : "";
|
||||
|
||||
@@ -97,10 +97,9 @@ export class HuiRepairsCard
|
||||
}
|
||||
|
||||
// Update visibility based on admin status and repairs count
|
||||
const shouldBeHidden = Boolean(
|
||||
const shouldBeHidden =
|
||||
!this.hass.user?.is_admin ||
|
||||
(this._config.hide_empty && this._repairsIssues.length === 0)
|
||||
);
|
||||
(this._config.hide_empty && this._repairsIssues.length === 0);
|
||||
|
||||
if (shouldBeHidden !== this.hidden) {
|
||||
this.style.display = shouldBeHidden ? "none" : "";
|
||||
|
||||
@@ -91,10 +91,9 @@ export class HuiUpdatesCard extends LitElement implements LovelaceCard {
|
||||
const updateEntities = this._getUpdateEntities();
|
||||
|
||||
// Update visibility based on admin status and updates count
|
||||
const shouldBeHidden = Boolean(
|
||||
const shouldBeHidden =
|
||||
!this.hass.user?.is_admin ||
|
||||
(this._config.hide_empty && updateEntities.length === 0)
|
||||
);
|
||||
(this._config.hide_empty && updateEntities.length === 0);
|
||||
|
||||
if (shouldBeHidden !== this.hidden) {
|
||||
this.style.display = shouldBeHidden ? "none" : "";
|
||||
@@ -104,7 +103,7 @@ export class HuiUpdatesCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this._config || !this.hass) {
|
||||
if (!this._config || !this.hass || this.hidden) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _measure() {
|
||||
this.narrow = this.offsetWidth < 425;
|
||||
this.narrow = this.offsetWidth < 450;
|
||||
this._collapseButtons = this.offsetWidth < 320;
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,6 @@ export class HuiDialogEditBadge
|
||||
.hass=${this.hass}
|
||||
.lovelace=${this._params.lovelaceConfig}
|
||||
.value=${this._badgeConfig}
|
||||
in-dialog
|
||||
@config-changed=${this._handleConfigChanged}
|
||||
@GUImode-changed=${this._handleGUIModeChanged}
|
||||
@editor-save=${this._save}
|
||||
@@ -315,9 +314,7 @@ export class HuiDialogEditBadge
|
||||
}
|
||||
|
||||
private _toggleMode(): void {
|
||||
withViewTransition(() => {
|
||||
this._badgeEditorEl?.toggleMode();
|
||||
});
|
||||
this._badgeEditorEl?.toggleMode();
|
||||
}
|
||||
|
||||
private _opened() {
|
||||
|
||||
@@ -97,7 +97,6 @@ export class HuiDialogSuggestBadge extends LitElement {
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._badgeConfig}
|
||||
in-dialog
|
||||
></ha-yaml-editor>
|
||||
</div>
|
||||
`
|
||||
|
||||
@@ -203,7 +203,6 @@ export class HuiDialogEditCard
|
||||
.hass=${this.hass}
|
||||
.lovelace=${this._params.lovelaceConfig}
|
||||
.value=${this._cardConfig}
|
||||
in-dialog
|
||||
@config-changed=${this._handleConfigChanged}
|
||||
@GUImode-changed=${this._handleGUIModeChanged}
|
||||
@editor-save=${this._save}
|
||||
@@ -298,9 +297,7 @@ export class HuiDialogEditCard
|
||||
}
|
||||
|
||||
private _toggleMode(): void {
|
||||
withViewTransition(() => {
|
||||
this._cardEditorEl?.toggleMode();
|
||||
});
|
||||
this._cardEditorEl?.toggleMode();
|
||||
}
|
||||
|
||||
private _opened() {
|
||||
|
||||
@@ -133,7 +133,6 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this._cardConfig}
|
||||
in-dialog
|
||||
></ha-yaml-editor>
|
||||
</div>
|
||||
`
|
||||
|
||||
@@ -57,9 +57,6 @@ export abstract class HuiElementEditor<
|
||||
|
||||
@property({ attribute: false }) public context?: C;
|
||||
|
||||
@property({ type: Boolean, attribute: "in-dialog" })
|
||||
public inDialog = false;
|
||||
|
||||
@state() private _config?: T;
|
||||
|
||||
@state() private _configElement?: LovelaceGenericElementEditor;
|
||||
@@ -153,9 +150,6 @@ export abstract class HuiElementEditor<
|
||||
}
|
||||
|
||||
public toggleMode() {
|
||||
if (!this.GUImode) {
|
||||
this._yamlEditor?.disableCodeEditorFullscreen();
|
||||
}
|
||||
this.GUImode = !this.GUImode;
|
||||
}
|
||||
|
||||
@@ -249,7 +243,6 @@ export abstract class HuiElementEditor<
|
||||
.defaultValue=${this._config}
|
||||
autofocus
|
||||
.hass=${this.hass}
|
||||
.inDialog=${this.inDialog}
|
||||
@value-changed=${this._handleYAMLChanged}
|
||||
@blur=${this._onBlurYaml}
|
||||
@keydown=${this._ignoreKeydown}
|
||||
|
||||
@@ -127,7 +127,6 @@ export class HuiDialogEditSection
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
autofocus
|
||||
in-dialog
|
||||
@value-changed=${this._viewYamlChanged}
|
||||
></ha-yaml-editor>
|
||||
`;
|
||||
|
||||
@@ -162,7 +162,6 @@ export class HuiDialogEditView extends LitElement {
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
autofocus
|
||||
in-dialog
|
||||
@value-changed=${this._viewYamlChanged}
|
||||
></ha-yaml-editor>
|
||||
`;
|
||||
|
||||
@@ -84,7 +84,6 @@ export class HuiDialogEditViewHeader extends LitElement {
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
autofocus
|
||||
in-dialog
|
||||
@value-changed=${this._viewYamlChanged}
|
||||
></ha-yaml-editor>
|
||||
`;
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
removeSearchParam,
|
||||
} from "../../common/url/search-params";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
import { deepEqual } from "../../common/util/deep-equal";
|
||||
import "../../components/ha-button";
|
||||
import { domainToName } from "../../data/integration";
|
||||
import { subscribeLovelaceUpdates } from "../../data/lovelace";
|
||||
@@ -36,7 +35,10 @@ import { checkLovelaceConfig } from "./common/check-lovelace-config";
|
||||
import { loadLovelaceResources } from "./common/load-resources";
|
||||
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
||||
import "./hui-root";
|
||||
import { generateLovelaceDashboardStrategy } from "./strategies/get-strategy";
|
||||
import {
|
||||
checkStrategyShouldRegenerate,
|
||||
generateLovelaceDashboardStrategy,
|
||||
} from "./strategies/get-strategy";
|
||||
import type { Lovelace } from "./types";
|
||||
import { generateDefaultView } from "./views/default-view";
|
||||
import { fetchDashboards } from "../../data/lovelace/dashboard";
|
||||
@@ -50,12 +52,6 @@ interface LovelacePanelConfig {
|
||||
let editorLoaded = false;
|
||||
let resourcesLoaded = false;
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"strategy-config-changed": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("ha-panel-lovelace")
|
||||
export class LovelacePanel extends LitElement {
|
||||
@property({ attribute: false }) public panel?: PanelInfo<
|
||||
@@ -129,7 +125,6 @@ export class LovelacePanel extends LitElement {
|
||||
.route=${this.route}
|
||||
.narrow=${this.narrow}
|
||||
@config-refresh=${this._forceFetchConfig}
|
||||
@strategy-config-changed=${this._strategyConfigChanged}
|
||||
></hui-root>
|
||||
`;
|
||||
}
|
||||
@@ -195,61 +190,25 @@ export class LovelacePanel extends LitElement {
|
||||
this.lovelace &&
|
||||
isStrategyDashboard(this.lovelace.rawConfig)
|
||||
) {
|
||||
// If the entity registry changed, ask the user if they want to refresh the config
|
||||
if (
|
||||
oldHass.entities !== this.hass.entities ||
|
||||
oldHass.devices !== this.hass.devices ||
|
||||
oldHass.areas !== this.hass.areas ||
|
||||
oldHass.floors !== this.hass.floors
|
||||
) {
|
||||
if (this.hass.config.state === "RUNNING") {
|
||||
this._debounceRegistriesChanged();
|
||||
}
|
||||
}
|
||||
// If ha started, refresh the config
|
||||
if (
|
||||
this.hass.config.state === "RUNNING" &&
|
||||
oldHass.config.state !== "RUNNING"
|
||||
checkStrategyShouldRegenerate(
|
||||
"dashboard",
|
||||
this.lovelace.rawConfig.strategy,
|
||||
oldHass,
|
||||
this.hass
|
||||
)
|
||||
) {
|
||||
this._regenerateStrategyConfig();
|
||||
this._debounceRegenerateStrategy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _debounceRegistriesChanged = debounce(
|
||||
() => this._registriesChanged(),
|
||||
private _debounceRegenerateStrategy = debounce(
|
||||
() => this._regenerateStrategyConfig(),
|
||||
200
|
||||
);
|
||||
|
||||
private _registriesChanged = async () => {
|
||||
if (!this.hass || !this.lovelace) {
|
||||
return;
|
||||
}
|
||||
const rawConfig = this.lovelace.rawConfig;
|
||||
|
||||
if (!isStrategyDashboard(rawConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldConfig = this.lovelace.config;
|
||||
const generatedConfig = await generateLovelaceDashboardStrategy(
|
||||
rawConfig,
|
||||
this.hass!
|
||||
);
|
||||
|
||||
const newConfig = checkLovelaceConfig(generatedConfig) as LovelaceConfig;
|
||||
|
||||
// Regenerate if the config changed
|
||||
if (!deepEqual(newConfig, oldConfig)) {
|
||||
this._regenerateStrategyConfig();
|
||||
}
|
||||
};
|
||||
|
||||
private _strategyConfigChanged = (ev: CustomEvent) => {
|
||||
ev.stopPropagation();
|
||||
this._regenerateStrategyConfig();
|
||||
};
|
||||
|
||||
private async _regenerateStrategyConfig() {
|
||||
if (!this.hass || !this.lovelace) {
|
||||
return;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ReactiveElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import type { LovelaceSectionElement } from "../../../data/lovelace";
|
||||
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
@@ -23,7 +24,10 @@ import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog"
|
||||
import { addCard, replaceCard } from "../editor/config-util";
|
||||
import { performDeleteCard } from "../editor/delete-card";
|
||||
import { parseLovelaceCardPath } from "../editor/lovelace-path";
|
||||
import { generateLovelaceSectionStrategy } from "../strategies/get-strategy";
|
||||
import {
|
||||
checkStrategyShouldRegenerate,
|
||||
generateLovelaceSectionStrategy,
|
||||
} from "../strategies/get-strategy";
|
||||
import type { Lovelace } from "../types";
|
||||
import { DEFAULT_SECTION_LAYOUT } from "./const";
|
||||
|
||||
@@ -104,9 +108,35 @@ export class HuiSection extends ConditionalListenerMixin<LovelaceSectionConfig>(
|
||||
(!oldConfig || this.config !== oldConfig)
|
||||
) {
|
||||
this._initializeConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!changedProperties.has("hass")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldHass = changedProperties.get("hass") as HomeAssistant | undefined;
|
||||
if (
|
||||
oldHass &&
|
||||
this.hass &&
|
||||
isStrategySection(this.config) &&
|
||||
this.hass.config.state === "RUNNING" &&
|
||||
checkStrategyShouldRegenerate(
|
||||
"section",
|
||||
this.config.strategy,
|
||||
oldHass,
|
||||
this.hass
|
||||
)
|
||||
) {
|
||||
this._debounceRefreshConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private _debounceRefreshConfig = debounce(
|
||||
() => this._initializeConfig(),
|
||||
200
|
||||
);
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,17 @@ export interface AreasDashboardStrategyConfig {
|
||||
|
||||
@customElement("areas-dashboard-strategy")
|
||||
export class AreasDashboardStrategy extends ReactiveElement {
|
||||
static shouldRegenerate(
|
||||
_config: AreasDashboardStrategyConfig,
|
||||
oldHass: HomeAssistant,
|
||||
newHass: HomeAssistant
|
||||
): boolean {
|
||||
return (
|
||||
oldHass.areas !== newHass.areas ||
|
||||
oldHass.config.state !== newHass.config.state
|
||||
);
|
||||
}
|
||||
|
||||
static async generate(
|
||||
config: AreasDashboardStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
|
||||
@@ -235,6 +235,50 @@ export const generateLovelaceSectionStrategy = async (
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Synchronously checks whether a strategy needs regeneration.
|
||||
* Falls back to checking common registries if the strategy doesn't implement shouldRegenerate.
|
||||
*/
|
||||
export const checkStrategyShouldRegenerate = (
|
||||
configType: LovelaceStrategyConfigType,
|
||||
strategyConfig: LovelaceStrategyConfig,
|
||||
oldHass: HomeAssistant,
|
||||
newHass: HomeAssistant
|
||||
): boolean => {
|
||||
const strategyType = strategyConfig.type;
|
||||
if (!strategyType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let strategy: LovelaceStrategy | undefined;
|
||||
|
||||
if (strategyType in STRATEGIES[configType]) {
|
||||
const tag = `${strategyType}-${configType}-strategy`;
|
||||
strategy = customElements.get(tag) as unknown as
|
||||
| LovelaceStrategy
|
||||
| undefined;
|
||||
} else if (strategyType.startsWith(CUSTOM_PREFIX)) {
|
||||
const name = strategyType.slice(CUSTOM_PREFIX.length);
|
||||
const tag = `ll-strategy-${configType}-${name}`;
|
||||
const legacyTag = `ll-strategy-${name}`;
|
||||
strategy = (customElements.get(tag) ??
|
||||
customElements.get(legacyTag)) as unknown as LovelaceStrategy | undefined;
|
||||
}
|
||||
|
||||
if (strategy?.shouldRegenerate) {
|
||||
return strategy.shouldRegenerate(strategyConfig, oldHass, newHass);
|
||||
}
|
||||
|
||||
// Default: check common registries for strategies without shouldRegenerate
|
||||
return (
|
||||
oldHass.entities !== newHass.entities ||
|
||||
oldHass.devices !== newHass.devices ||
|
||||
oldHass.areas !== newHass.areas ||
|
||||
oldHass.floors !== newHass.floors ||
|
||||
oldHass.config.state !== newHass.config.state
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find all references to strategies and replaces them with the generated output
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,17 @@ export interface HomeDashboardStrategyConfig {
|
||||
|
||||
@customElement("home-dashboard-strategy")
|
||||
export class HomeDashboardStrategy extends ReactiveElement {
|
||||
static shouldRegenerate(
|
||||
_config: HomeDashboardStrategyConfig,
|
||||
oldHass: HomeAssistant,
|
||||
newHass: HomeAssistant
|
||||
): boolean {
|
||||
return (
|
||||
oldHass.areas !== newHass.areas ||
|
||||
oldHass.config.state !== newHass.config.state
|
||||
);
|
||||
}
|
||||
|
||||
static async generate(
|
||||
config: HomeDashboardStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceStrategyEditor } from "../types";
|
||||
import type { IframeViewStrategyConfig } from "./iframe-view-strategy";
|
||||
|
||||
@@ -8,6 +9,14 @@ export type IframeDashboardStrategyConfig = IframeViewStrategyConfig;
|
||||
|
||||
@customElement("iframe-dashboard-strategy")
|
||||
export class IframeDashboardStrategy extends ReactiveElement {
|
||||
static shouldRegenerate(
|
||||
_config: IframeDashboardStrategyConfig,
|
||||
_oldHass: HomeAssistant,
|
||||
_newHass: HomeAssistant
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
static async generate(
|
||||
config: IframeDashboardStrategyConfig
|
||||
): Promise<LovelaceConfig> {
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { MapViewStrategyConfig } from "./map-view-strategy";
|
||||
|
||||
export type MapDashboardStrategyConfig = MapViewStrategyConfig;
|
||||
|
||||
@customElement("map-dashboard-strategy")
|
||||
export class MapDashboardStrategy extends ReactiveElement {
|
||||
static shouldRegenerate(
|
||||
_config: MapDashboardStrategyConfig,
|
||||
_oldHass: HomeAssistant,
|
||||
_newHass: HomeAssistant
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
static async generate(
|
||||
config: MapDashboardStrategyConfig
|
||||
): Promise<LovelaceConfig> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceStrategyEditor } from "../types";
|
||||
import type { OriginalStatesViewStrategyConfig } from "./original-states-view-strategy";
|
||||
|
||||
@@ -9,6 +10,14 @@ export type OriginalStatesDashboardStrategyConfig =
|
||||
|
||||
@customElement("original-states-dashboard-strategy")
|
||||
export class OriginalStatesDashboardStrategy extends ReactiveElement {
|
||||
static shouldRegenerate(
|
||||
_config: OriginalStatesDashboardStrategyConfig,
|
||||
_oldHass: HomeAssistant,
|
||||
_newHass: HomeAssistant
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
static async generate(
|
||||
config: OriginalStatesDashboardStrategyConfig
|
||||
): Promise<LovelaceConfig> {
|
||||
|
||||
@@ -7,6 +7,11 @@ import type { LovelaceGenericElementEditor } from "../types";
|
||||
|
||||
export interface LovelaceStrategy<T = any> {
|
||||
generate(config: LovelaceStrategyConfig, hass: HomeAssistant): Promise<T>;
|
||||
shouldRegenerate?(
|
||||
config: LovelaceStrategyConfig,
|
||||
oldHass: HomeAssistant,
|
||||
newHass: HomeAssistant
|
||||
): boolean;
|
||||
getConfigElement?: () => LovelaceStrategyEditor;
|
||||
noEditor?: boolean;
|
||||
configRequired?: boolean;
|
||||
|
||||
@@ -241,9 +241,8 @@ export class HuiViewFooter extends LitElement {
|
||||
box-sizing: content-box;
|
||||
margin: 0 auto;
|
||||
max-width: calc(
|
||||
var(--footer-column-span, 1) / var(--column-count, 1) * 100% +
|
||||
(var(--footer-column-span, 1) - var(--column-count, 1)) /
|
||||
var(--column-count, 1) * var(--column-gap, 32px)
|
||||
var(--footer-column-span, 1) * var(--column-max-width, 500px) +
|
||||
(var(--footer-column-span, 1) - 1) * var(--column-gap, 32px)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ import type { PropertyValues } from "lit";
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import { fireEvent, type HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
|
||||
import "../../../components/entity/ha-state-label-badge";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import type { LovelaceViewElement } from "../../../data/lovelace";
|
||||
@@ -42,7 +42,10 @@ import { parseLovelaceCardPath } from "../editor/lovelace-path";
|
||||
import { createErrorSectionConfig } from "../sections/hui-error-section";
|
||||
import "../sections/hui-section";
|
||||
import type { HuiSection } from "../sections/hui-section";
|
||||
import { generateLovelaceViewStrategy } from "../strategies/get-strategy";
|
||||
import {
|
||||
checkStrategyShouldRegenerate,
|
||||
generateLovelaceViewStrategy,
|
||||
} from "../strategies/get-strategy";
|
||||
import type { Lovelace } from "../types";
|
||||
import { getViewType } from "./get-view-type";
|
||||
|
||||
@@ -90,10 +93,6 @@ export class HUIView extends ReactiveElement {
|
||||
|
||||
private _layoutElement?: LovelaceViewElement;
|
||||
|
||||
private _layoutElementConfig?: LovelaceViewConfig;
|
||||
|
||||
private _rendered = false;
|
||||
|
||||
@storage({
|
||||
key: "dashboardCardClipboard",
|
||||
state: false,
|
||||
@@ -154,18 +153,6 @@ export class HUIView extends ReactiveElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.updateComplete.then(() => {
|
||||
this._rendered = true;
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._rendered = false;
|
||||
}
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues<typeof this>): void {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
@@ -201,51 +188,24 @@ export class HUIView extends ReactiveElement {
|
||||
const viewConfig = this.lovelace.config.views[this.index];
|
||||
if (oldHass && this.hass && this.lovelace && isStrategyView(viewConfig)) {
|
||||
if (
|
||||
oldHass.entities !== this.hass.entities ||
|
||||
oldHass.devices !== this.hass.devices ||
|
||||
oldHass.areas !== this.hass.areas ||
|
||||
oldHass.floors !== this.hass.floors
|
||||
this.hass.config.state === "RUNNING" &&
|
||||
checkStrategyShouldRegenerate(
|
||||
"view",
|
||||
viewConfig.strategy,
|
||||
oldHass,
|
||||
this.hass
|
||||
)
|
||||
) {
|
||||
if (this.hass.config.state === "RUNNING") {
|
||||
// If the page is not rendered yet, we can force the refresh
|
||||
if (this._rendered) {
|
||||
this._debounceRefreshConfig(false);
|
||||
} else {
|
||||
this._refreshConfig(true);
|
||||
}
|
||||
}
|
||||
this._debounceRefreshConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _debounceRefreshConfig = debounce(
|
||||
(force: boolean) => this._refreshConfig(force),
|
||||
() => this._initializeConfig(),
|
||||
200
|
||||
);
|
||||
|
||||
private _refreshConfig = async (force: boolean) => {
|
||||
if (!this.hass || !this.lovelace) {
|
||||
return;
|
||||
}
|
||||
const viewConfig = this.lovelace.config.views[this.index];
|
||||
|
||||
if (!isStrategyView(viewConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldConfig = this._layoutElementConfig;
|
||||
const newConfig = await this._generateConfig(viewConfig);
|
||||
|
||||
// Don't ask if the config is the same
|
||||
if (!deepEqual(newConfig, oldConfig)) {
|
||||
if (force) {
|
||||
this._setConfig(newConfig, true);
|
||||
} else {
|
||||
fireEvent(this, "strategy-config-changed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected update(changedProperties: PropertyValues) {
|
||||
super.update(changedProperties);
|
||||
|
||||
@@ -332,7 +292,6 @@ export class HUIView extends ReactiveElement {
|
||||
addLayoutElement = true;
|
||||
this._createLayoutElement(viewConfig);
|
||||
}
|
||||
this._layoutElementConfig = viewConfig;
|
||||
this._createBadges(viewConfig);
|
||||
this._createCards(viewConfig);
|
||||
this._createSections(viewConfig);
|
||||
|
||||
Reference in New Issue
Block a user