Skip to content

Commit 7742ccf

Browse files
piitayabramkragten
authored andcommitted
Only ask to refresh dashboard if necessary (#24993)
1 parent 20f2a8d commit 7742ccf

File tree

2 files changed

+155
-19
lines changed

2 files changed

+155
-19
lines changed

src/panels/lovelace/ha-panel-lovelace.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
addSearchParam,
1010
removeSearchParam,
1111
} from "../../common/url/search-params";
12+
import { debounce } from "../../common/util/debounce";
13+
import { deepEqual } from "../../common/util/deep-equal";
1214
import { domainToName } from "../../data/integration";
1315
import { subscribeLovelaceUpdates } from "../../data/lovelace";
1416
import type {
@@ -51,6 +53,12 @@ interface LovelacePanelConfig {
5153
let editorLoaded = false;
5254
let resourcesLoaded = false;
5355

56+
declare global {
57+
interface HASSDomEvents {
58+
"strategy-config-changed": undefined;
59+
}
60+
}
61+
5462
@customElement("ha-panel-lovelace")
5563
export class LovelacePanel extends LitElement {
5664
@property({ attribute: false }) public panel?: PanelInfo<LovelacePanelConfig>;
@@ -127,6 +135,7 @@ export class LovelacePanel extends LitElement {
127135
.route=${this.route}
128136
.narrow=${this.narrow}
129137
@config-refresh=${this._forceFetchConfig}
138+
@strategy-config-changed=${this._strategyConfigChanged}
130139
></hui-root>
131140
`;
132141
}
@@ -199,33 +208,67 @@ export class LovelacePanel extends LitElement {
199208
oldHass.floors !== this.hass.floors
200209
) {
201210
if (this.hass.config.state === "RUNNING") {
202-
this._askRefreshConfig();
211+
this._debounceRegistriesChanged();
203212
}
204213
}
205214
// If ha started, refresh the config
206215
if (
207216
this.hass.config.state === "RUNNING" &&
208217
oldHass.config.state !== "RUNNING"
209218
) {
210-
this._refreshConfig();
219+
this._regenerateStrategyConfig();
211220
}
212221
}
213222
}
214223

215-
private _askRefreshConfig = () => {
224+
private _debounceRegistriesChanged = debounce(
225+
() => this._registriesChanged(),
226+
200
227+
);
228+
229+
private _registriesChanged = async () => {
230+
if (!this.hass || !this.lovelace) {
231+
return;
232+
}
233+
const rawConfig = this.lovelace.rawConfig;
234+
235+
if (!isStrategyDashboard(rawConfig)) {
236+
return;
237+
}
238+
239+
const oldConfig = this.lovelace.config;
240+
const generatedConfig = await generateLovelaceDashboardStrategy(
241+
rawConfig,
242+
this.hass!
243+
);
244+
245+
const newConfig = checkLovelaceConfig(generatedConfig) as LovelaceConfig;
246+
247+
// Ask to regenerate if the config changed
248+
if (!deepEqual(newConfig, oldConfig)) {
249+
this._askRegenerateStrategyConfig();
250+
}
251+
};
252+
253+
private _strategyConfigChanged = (ev: CustomEvent) => {
254+
ev.stopPropagation();
255+
this._askRegenerateStrategyConfig();
256+
};
257+
258+
private _askRegenerateStrategyConfig = () => {
216259
showToast(this, {
217260
message: this.hass!.localize("ui.panel.lovelace.changed_toast.message"),
218261
action: {
219-
action: () => this._refreshConfig(),
262+
action: () => this._regenerateStrategyConfig(),
220263
text: this.hass!.localize("ui.common.refresh"),
221264
},
222265
duration: -1,
223-
id: "entity-registry-changed",
266+
id: "regenerate-strategy-config",
224267
dismissable: false,
225268
});
226269
};
227270

228-
private async _refreshConfig() {
271+
private async _regenerateStrategyConfig() {
229272
if (!this.hass || !this.lovelace) {
230273
return;
231274
}

src/panels/lovelace/views/hui-view.ts

Lines changed: 106 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ import type { PropertyValues } from "lit";
33
import { ReactiveElement } from "lit";
44
import { customElement, property, state } from "lit/decorators";
55
import { storage } from "../../../common/decorators/storage";
6-
import type { HASSDomEvent } from "../../../common/dom/fire_event";
6+
import { fireEvent, type HASSDomEvent } from "../../../common/dom/fire_event";
7+
import { debounce } from "../../../common/util/debounce";
8+
import { deepEqual } from "../../../common/util/deep-equal";
79
import "../../../components/entity/ha-state-label-badge";
810
import "../../../components/ha-svg-icon";
911
import type { LovelaceViewElement } from "../../../data/lovelace";
1012
import type { LovelaceBadgeConfig } from "../../../data/lovelace/config/badge";
1113
import { ensureBadgeConfig } from "../../../data/lovelace/config/badge";
1214
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
1315
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
14-
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
16+
import type {
17+
LovelaceViewConfig,
18+
LovelaceViewRawConfig,
19+
} from "../../../data/lovelace/config/view";
1520
import { isStrategyView } from "../../../data/lovelace/config/view";
1621
import type { HomeAssistant } from "../../../types";
1722
import "../badges/hui-badge";
@@ -85,6 +90,10 @@ export class HUIView extends ReactiveElement {
8590

8691
private _layoutElement?: LovelaceViewElement;
8792

93+
private _layoutElementConfig?: LovelaceViewConfig;
94+
95+
private _rendered = false;
96+
8897
@storage({
8998
key: "dashboardCardClipboard",
9099
state: false,
@@ -145,6 +154,18 @@ export class HUIView extends ReactiveElement {
145154
return this;
146155
}
147156

157+
connectedCallback(): void {
158+
super.connectedCallback();
159+
this.updateComplete.then(() => {
160+
this._rendered = true;
161+
});
162+
}
163+
164+
disconnectedCallback(): void {
165+
super.disconnectedCallback();
166+
this._rendered = false;
167+
}
168+
148169
public willUpdate(changedProperties: PropertyValues<typeof this>): void {
149170
super.willUpdate(changedProperties);
150171

@@ -169,9 +190,62 @@ export class HUIView extends ReactiveElement {
169190
oldLovelace.config.views[this.index]))
170191
) {
171192
this._initializeConfig();
193+
return;
194+
}
195+
196+
if (!changedProperties.has("hass")) {
197+
return;
198+
}
199+
200+
const oldHass = changedProperties.get("hass") as HomeAssistant | undefined;
201+
const viewConfig = this.lovelace.config.views[this.index];
202+
if (oldHass && this.hass && this.lovelace && isStrategyView(viewConfig)) {
203+
if (
204+
oldHass.entities !== this.hass.entities ||
205+
oldHass.devices !== this.hass.devices ||
206+
oldHass.areas !== this.hass.areas ||
207+
oldHass.floors !== this.hass.floors
208+
) {
209+
if (this.hass.config.state === "RUNNING") {
210+
// If the page is not rendered yet, we can force the refresh
211+
if (this._rendered) {
212+
this._debounceRefreshConfig(false);
213+
} else {
214+
this._refreshConfig(true);
215+
}
216+
}
217+
}
172218
}
173219
}
174220

221+
private _debounceRefreshConfig = debounce(
222+
(force: boolean) => this._refreshConfig(force),
223+
200
224+
);
225+
226+
private _refreshConfig = async (force: boolean) => {
227+
if (!this.hass || !this.lovelace) {
228+
return;
229+
}
230+
const viewConfig = this.lovelace.config.views[this.index];
231+
232+
if (!isStrategyView(viewConfig)) {
233+
return;
234+
}
235+
236+
const oldConfig = this._layoutElementConfig;
237+
const newConfig = await this._generateConfig(viewConfig);
238+
239+
// Don't ask if the config is the same
240+
if (!deepEqual(newConfig, oldConfig)) {
241+
if (force) {
242+
this._setConfig(newConfig, true);
243+
} else {
244+
fireEvent(this, "strategy-config-changed");
245+
}
246+
}
247+
};
248+
175249
protected update(changedProperties: PropertyValues) {
176250
super.update(changedProperties);
177251

@@ -227,28 +301,38 @@ export class HUIView extends ReactiveElement {
227301
}
228302
}
229303

230-
private async _initializeConfig() {
231-
let viewConfig = this.lovelace.config.views[this.index];
232-
let isStrategy = false;
233-
234-
if (isStrategyView(viewConfig)) {
235-
isStrategy = true;
236-
viewConfig = await generateLovelaceViewStrategy(viewConfig, this.hass!);
304+
private async _generateConfig(
305+
config: LovelaceViewRawConfig
306+
): Promise<LovelaceViewConfig> {
307+
if (isStrategyView(config)) {
308+
const generatedConfig = await generateLovelaceViewStrategy(
309+
config,
310+
this.hass!
311+
);
312+
return {
313+
...generatedConfig,
314+
type: getViewType(generatedConfig),
315+
};
237316
}
238317

239-
viewConfig = {
240-
...viewConfig,
241-
type: getViewType(viewConfig),
318+
return {
319+
...config,
320+
type: getViewType(config),
242321
};
322+
}
243323

324+
private async _setConfig(
325+
viewConfig: LovelaceViewConfig,
326+
isStrategy: boolean
327+
) {
244328
// Create a new layout element if necessary.
245329
let addLayoutElement = false;
246330

247331
if (!this._layoutElement || this._layoutElementType !== viewConfig.type) {
248332
addLayoutElement = true;
249333
this._createLayoutElement(viewConfig);
250334
}
251-
335+
this._layoutElementConfig = viewConfig;
252336
this._createBadges(viewConfig);
253337
this._createCards(viewConfig);
254338
this._createSections(viewConfig);
@@ -269,6 +353,15 @@ export class HUIView extends ReactiveElement {
269353
}
270354
}
271355

356+
private async _initializeConfig() {
357+
const rawConfig = this.lovelace.config.views[this.index];
358+
359+
const viewConfig = await this._generateConfig(rawConfig);
360+
const isStrategy = isStrategyView(viewConfig);
361+
362+
this._setConfig(viewConfig, isStrategy);
363+
}
364+
272365
private _createLayoutElement(config: LovelaceViewConfig): void {
273366
this._layoutElement = createViewElement(config) as LovelaceViewElement;
274367
this._layoutElementType = config.type;

0 commit comments

Comments
 (0)