Skip to content

Commit

Permalink
Avoid flickering when moving element in the dashboard (#1661)
Browse files Browse the repository at this point in the history
* Add cache manager

* Use cache for all templates

* Rollback plugin serve
  • Loading branch information
piitaya authored Feb 28, 2025
1 parent fa4e496 commit 3d82e7b
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 40 deletions.
52 changes: 32 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"home-assistant-js-websocket": "^9.4.0",
"lit": "^3.2.1",
"memoize-one": "^6.0.0",
"object-hash": "^3.0.0",
"sortablejs": "^1.15.6",
"superstruct": "^2.0.2"
},
Expand All @@ -44,7 +45,7 @@
"eslint": "^9.21.0",
"prettier": "^3.5.2",
"rollup": "^4.34.8",
"rollup-plugin-serve": "^3.0.0",
"rollup-plugin-serve": "^1.1.1",
"typescript": "^5.7.3"
}
}
43 changes: 37 additions & 6 deletions src/badges/template/template-badge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { customElement, property, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { styleMap } from "lit/directives/style-map.js";
import hash from "object-hash/dist/object_hash";
import {
actionHandler,
ActionHandlerEvent,
Expand All @@ -24,10 +25,17 @@ import {
} from "../../ha";
import { computeCssColor } from "../../ha/common/color/compute-color";
import { registerCustomBadge } from "../../utils/custom-badges";
import { TEMPLATE_BADGE_EDITOR_NAME, TEMPLATE_BADGE_NAME } from "./const";
import { TemplateBadgeConfig } from "./template-badge-config";
import { getWeatherSvgIcon } from "../../utils/icons/weather-icon";
import { weatherSVGStyles } from "../../utils/weather";
import { TEMPLATE_BADGE_EDITOR_NAME, TEMPLATE_BADGE_NAME } from "./const";
import { TemplateBadgeConfig } from "./template-badge-config";
import { CacheManager } from "../../utils/cache-manager";

const templateCache = new CacheManager<TemplateResults>(1000);

type TemplateResults = Partial<
Record<TemplateKey, RenderTemplateResult | undefined>
>;

registerCustomBadge({
type: TEMPLATE_BADGE_NAME,
Expand Down Expand Up @@ -62,9 +70,7 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {

@state() protected _config?: TemplateBadgeConfig;

@state() private _templateResults: Partial<
Record<TemplateKey, RenderTemplateResult | undefined>
> = {};
@state() private _templateResults?: TemplateResults;

@state() private _unsubRenderTemplates: Map<
TemplateKey,
Expand All @@ -77,9 +83,34 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
}

public disconnectedCallback() {
super.disconnectedCallback();
this._tryDisconnect();

if (this._config && this._templateResults) {
const key = this._computeCacheKey();
templateCache.set(key, this._templateResults);
}
}

private _computeCacheKey() {
return hash(this._config);
}

protected willUpdate(_changedProperties: PropertyValues): void {
super.willUpdate(_changedProperties);
if (!this._config) {
return;
}

if (!this._templateResults) {
const key = this._computeCacheKey();
if (templateCache.has(key)) {
this._templateResults = templateCache.get(key)!;
} else {
this._templateResults = {};
}
}
}
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
if (!this._config || !this.hass) {
Expand Down Expand Up @@ -267,7 +298,7 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {

private getValue(key: TemplateKey) {
return this.isTemplate(key)
? this._templateResults[key]?.result?.toString()
? this._templateResults?.[key]?.result?.toString()
: this._config?.[key];
}

Expand Down
42 changes: 37 additions & 5 deletions src/cards/chips-card/chips/template-chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { styleMap } from "lit/directives/style-map.js";
import hash from "object-hash/dist/object_hash";
import {
actionHandler,
ActionHandlerEvent,
Expand All @@ -20,6 +21,7 @@ import {
RenderTemplateResult,
subscribeRenderTemplate,
} from "../../../ha";
import { CacheManager } from "../../../utils/cache-manager";
import { computeRgbColor } from "../../../utils/colors";
import { getWeatherSvgIcon } from "../../../utils/icons/weather-icon";
import {
Expand All @@ -33,6 +35,12 @@ import {
import { LovelaceChipEditor } from "../../../utils/lovelace/types";
import { weatherSVGStyles } from "../../../utils/weather";

const templateCache = new CacheManager<TemplateResults>(1000);

type TemplateResults = Partial<
Record<TemplateKey, RenderTemplateResult | undefined>
>;

const TEMPLATE_KEYS = ["content", "icon", "icon_color", "picture"] as const;
type TemplateKey = (typeof TEMPLATE_KEYS)[number];

Expand All @@ -57,9 +65,7 @@ export class TemplateChip extends LitElement implements LovelaceChip {

@state() private _config?: TemplateChipConfig;

@state() private _templateResults: Partial<
Record<TemplateKey, RenderTemplateResult | undefined>
> = {};
@state() private _templateResults?: TemplateResults;

@state() private _unsubRenderTemplates: Map<
TemplateKey,
Expand Down Expand Up @@ -92,7 +98,33 @@ export class TemplateChip extends LitElement implements LovelaceChip {
}

public disconnectedCallback() {
super.disconnectedCallback();
this._tryDisconnect();

if (this._config && this._templateResults) {
const key = this._computeCacheKey();
templateCache.set(key, this._templateResults);
}
}

private _computeCacheKey() {
return hash(this._config);
}

protected willUpdate(_changedProperties: PropertyValues): void {
super.willUpdate(_changedProperties);
if (!this._config) {
return;
}

if (!this._templateResults) {
const key = this._computeCacheKey();
if (templateCache.has(key)) {
this._templateResults = templateCache.get(key)!;
} else {
this._templateResults = {};
}
}
}

private _handleAction(ev: ActionHandlerEvent) {
Expand All @@ -106,7 +138,7 @@ export class TemplateChip extends LitElement implements LovelaceChip {

private getValue(key: TemplateKey) {
return this.isTemplate(key)
? this._templateResults[key]?.result?.toString()
? this._templateResults?.[key]?.result?.toString()
: this._config?.[key];
}

Expand All @@ -132,7 +164,7 @@ export class TemplateChip extends LitElement implements LovelaceChip {
hasDoubleClick: hasAction(this._config.double_tap_action),
})}
.avatar=${picture ? (this.hass as any).hassUrl(picture) : undefined}
.avatarOnly=${picture && !content}
.avatarOnly=${(picture && !content) || false}
>
${!picture
? weatherSvg
Expand Down
40 changes: 36 additions & 4 deletions src/cards/template-card/template-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { customElement, property, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { styleMap } from "lit/directives/style-map.js";
import hash from "object-hash/dist/object_hash";
import {
actionHandler,
ActionHandlerEvent,
Expand All @@ -29,6 +30,7 @@ import "../../shared/state-info";
import "../../shared/state-item";
import { computeAppearance } from "../../utils/appearance";
import { MushroomBaseElement } from "../../utils/base-element";
import { CacheManager } from "../../utils/cache-manager";
import { cardStyle } from "../../utils/card-styles";
import { computeRgbColor } from "../../utils/colors";
import { registerCustomCard } from "../../utils/custom-cards";
Expand All @@ -37,6 +39,12 @@ import { weatherSVGStyles } from "../../utils/weather";
import { TEMPLATE_CARD_EDITOR_NAME, TEMPLATE_CARD_NAME } from "./const";
import { TemplateCardConfig } from "./template-card-config";

const templateCache = new CacheManager<TemplateResults>(1000);

type TemplateResults = Partial<
Record<TemplateKey, RenderTemplateResult | undefined>
>;

registerCustomCard({
type: TEMPLATE_CARD_NAME,
name: "Mushroom Template",
Expand Down Expand Up @@ -76,9 +84,7 @@ export class TemplateCard extends MushroomBaseElement implements LovelaceCard {

@state() private _config?: TemplateCardConfig;

@state() private _templateResults: Partial<
Record<TemplateKey, RenderTemplateResult | undefined>
> = {};
@state() private _templateResults?: TemplateResults;

@state() private _unsubRenderTemplates: Map<
TemplateKey,
Expand Down Expand Up @@ -164,7 +170,33 @@ export class TemplateCard extends MushroomBaseElement implements LovelaceCard {
}

public disconnectedCallback() {
super.disconnectedCallback();
this._tryDisconnect();

if (this._config && this._templateResults) {
const key = this._computeCacheKey();
templateCache.set(key, this._templateResults);
}
}

private _computeCacheKey() {
return hash(this._config);
}

protected willUpdate(_changedProperties: PropertyValues): void {
super.willUpdate(_changedProperties);
if (!this._config) {
return;
}

if (!this._templateResults) {
const key = this._computeCacheKey();
if (templateCache.has(key)) {
this._templateResults = templateCache.get(key)!;
} else {
this._templateResults = {};
}
}
}

private _handleAction(ev: ActionHandlerEvent) {
Expand All @@ -178,7 +210,7 @@ export class TemplateCard extends MushroomBaseElement implements LovelaceCard {

private getValue(key: TemplateKey) {
return this.isTemplate(key)
? this._templateResults[key]?.result?.toString()
? this._templateResults?.[key]?.result?.toString()
: this._config?.[key];
}

Expand Down
Loading

0 comments on commit 3d82e7b

Please sign in to comment.