Fix decorators with properties (#25282)

* Fix decorators with properties

* Green build

---------

Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com>
This commit is contained in:
Bram Kragten 2025-05-02 19:21:38 +03:00
parent 678a8a85cb
commit a820cd4576
39 changed files with 62 additions and 28 deletions

View File

@ -1,6 +1,5 @@
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import { ReactiveElement } from "lit";
import type { InternalPropertyDeclaration } from "lit/decorators";
import type { ReactiveElement } from "lit";
type Callback = (oldValue: any, newValue: any) => void;
@ -108,7 +107,6 @@ export function storage(options: {
storage?: "localStorage" | "sessionStorage";
subscribe?: boolean;
state?: boolean;
stateOptions?: InternalPropertyDeclaration;
serializer?: (value: any) => any;
deserializer?: (value: any) => any;
}) {
@ -174,7 +172,7 @@ export function storage(options: {
performUpdate.call(this);
};
if (options.state && options.subscribe) {
if (options.subscribe) {
const connectedCallback = proto.connectedCallback;
const disconnectedCallback = proto.disconnectedCallback;
@ -192,12 +190,6 @@ export function storage(options: {
el.__unbsubLocalStorage = undefined;
};
}
if (options.state) {
ReactiveElement.createProperty(propertyKey, {
noAccessor: true,
...options.stateOptions,
});
}
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;

View File

@ -1,10 +1,4 @@
import {
ReactiveElement,
type PropertyDeclaration,
type PropertyValues,
} from "lit";
import { shallowEqual } from "../util/shallow-equal";
import type { ReactiveElement, PropertyValues } from "lit";
/**
* Transform function type.
*/
@ -23,7 +17,6 @@ type ReactiveTransformElement = ReactiveElement & {
export function transform<T, V>(config: {
transformer: Transformer<T, V>;
watch?: PropertyKey[];
propertyOptions?: PropertyDeclaration;
}) {
return <ElemClass extends ReactiveElement>(
proto: ElemClass,
@ -84,11 +77,6 @@ export function transform<T, V>(config: {
curWatch.add(propertyKey);
});
}
ReactiveElement.createProperty(propertyKey, {
noAccessor: true,
hasChanged: (v: any, o: any) => !shallowEqual(v, o),
...config.propertyOptions,
});
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;

View File

@ -210,6 +210,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
private _unsubPersistentNotifications: UnsubscribeFunc | undefined;
@state()
@storage({
key: "sidebarPanelOrder",
state: true,
@ -217,6 +218,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
})
private _panelOrder: string[] = [];
@state()
@storage({
key: "sidebarHiddenPanels",
state: true,

View File

@ -42,6 +42,7 @@ class BrowseMediaTTS extends LitElement {
@state() private _provider?: TTSEngine;
@state()
@storage({
key: "TtsMessage",
state: true,

View File

@ -36,6 +36,7 @@ export class HaVoiceCommandDialog extends LitElement {
@state() private _opened = false;
@state()
@storage({
key: "AssistPipelineId",
state: true,

View File

@ -42,6 +42,7 @@ class PanelCalendar extends LitElement {
@state() private _error?: string = undefined;
@state()
@storage({
key: "deSelectedCalendars",
state: true,

View File

@ -69,6 +69,7 @@ export class HaConfigApplicationCredentials extends LitElement {
})
private _activeHiddenColumns?: string[];
@state()
@storage({
storage: "sessionStorage",
key: "application-credentials-table-search",

View File

@ -36,6 +36,7 @@ export default class HaAutomationAction extends LitElement {
@state() private _showReorder = false;
@state()
@storage({
key: "automationClipboard",
state: true,

View File

@ -36,6 +36,7 @@ export default class HaAutomationCondition extends LitElement {
@state() private _showReorder = false;
@state()
@storage({
key: "automationClipboard",
state: true,

View File

@ -135,6 +135,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
@state() private _blueprintConfig?: BlueprintAutomationConfig;
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
@transform<EntityRegistryEntry[], EntityRegistryEntry>({
transformer: function (this: HaAutomationEditor, value) {

View File

@ -138,6 +138,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
@state() private _filteredAutomations?: string[] | null;
@state()
@storage({
storage: "sessionStorage",
key: "automation-table-search",
@ -146,6 +147,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
})
private _filter = "";
@state()
@storage({
storage: "sessionStorage",
key: "automation-table-filters-full",

View File

@ -29,6 +29,7 @@ export default class HaAutomationOption extends LitElement {
@state() private _showReorder = false;
@state()
@storage({
key: "automationClipboard",
state: true,

View File

@ -38,6 +38,7 @@ export default class HaAutomationTrigger extends LitElement {
@state() private _showReorder = false;
@state()
@storage({
key: "automationClipboard",
state: true,

View File

@ -98,6 +98,7 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
@state() private _selected: string[] = [];
@state()
@storage({
storage: "sessionStorage",
key: "backups-table-filters",

View File

@ -9,7 +9,7 @@ import {
} from "@mdi/js";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, html } from "lit";
import { customElement, property } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { fireEvent } from "../../../common/dom/fire_event";
@ -118,6 +118,7 @@ class HaBlueprintOverview extends LitElement {
})
private _activeHiddenColumns?: string[];
@state()
@storage({
storage: "sessionStorage",
key: "blueprint-table-search",
@ -499,9 +500,11 @@ class HaBlueprintOverview extends LitElement {
list: html`<ul>
${[...(related.automation || []), ...(related.script || [])].map(
(item) => {
const state = this.hass.states[item];
const automationState = this.hass.states[item];
return html`<li>
${state ? `${computeStateName(state)} (${item})` : item}
${automationState
? `${computeStateName(automationState)} (${item})`
: item}
</li>`;
}
)}

View File

@ -120,6 +120,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
@state() private _selected: string[] = [];
@state()
@storage({
storage: "sessionStorage",
key: "devices-table-search",
@ -128,6 +129,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
})
private _filter: string = history.state?.filter || "";
@state()
@storage({
storage: "sessionStorage",
key: "devices-table-filters-full",

View File

@ -159,6 +159,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
@consume({ context: fullEntitiesContext, subscribe: true })
_entities!: EntityRegistryEntry[];
@state()
@storage({
storage: "sessionStorage",
key: "entities-table-search",
@ -169,6 +170,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
@state() private _searchParms = new URLSearchParams(window.location.search);
@state()
@storage({
storage: "sessionStorage",
key: "entities-table-filters",

View File

@ -168,6 +168,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
})
private _activeCollapsed?: string;
@state()
@storage({
storage: "sessionStorage",
key: "helpers-table-search",

View File

@ -1,7 +1,7 @@
import "@material/mwc-button";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { storage } from "../../../../../common/decorators/storage";
import "../../../../../components/ha-card";
import "../../../../../components/ha-code-editor";
@ -23,6 +23,7 @@ export class MQTTConfigPanel extends LitElement {
@property({ type: Boolean }) public narrow = false;
@state()
@storage({
key: "panel-dev-mqtt-topic-ls",
state: true,
@ -30,6 +31,7 @@ export class MQTTConfigPanel extends LitElement {
})
private _topic = "";
@state()
@storage({
key: "panel-dev-mqtt-payload-ls",
state: true,
@ -37,6 +39,7 @@ export class MQTTConfigPanel extends LitElement {
})
private _payload = "";
@state()
@storage({
key: "panel-dev-mqtt-qos-ls",
state: true,
@ -44,6 +47,7 @@ export class MQTTConfigPanel extends LitElement {
})
private _qos = "0";
@state()
@storage({
key: "panel-dev-mqtt-retain-ls",
state: true,
@ -51,6 +55,7 @@ export class MQTTConfigPanel extends LitElement {
})
private _retain = false;
@state()
@storage({
key: "panel-dev-mqtt-allow-template-ls",
state: true,

View File

@ -21,6 +21,7 @@ const qosLevel = ["0", "1", "2"];
class MqttSubscribeCard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state()
@storage({
key: "panel-dev-mqtt-topic-subscribe",
state: true,
@ -28,6 +29,7 @@ class MqttSubscribeCard extends LitElement {
})
private _topic = "";
@state()
@storage({
key: "panel-dev-mqtt-qos-subscribe",
state: true,
@ -35,6 +37,7 @@ class MqttSubscribeCard extends LitElement {
})
private _qos = "0";
@state()
@storage({
key: "panel-dev-mqtt-json-format",
state: true,

View File

@ -55,6 +55,7 @@ export class HaConfigLabels extends LitElement {
@state() private _labels: LabelRegistryEntry[] = [];
@state()
@storage({
storage: "sessionStorage",
key: "labels-table-search",

View File

@ -74,6 +74,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
@state() private _dashboards: LovelaceDashboard[] = [];
@state()
@storage({
storage: "sessionStorage",
key: "lovelace-dashboards-table-search",

View File

@ -46,6 +46,7 @@ export class HaConfigLovelaceRescources extends LitElement {
@state() private _resources: LovelaceResource[] = [];
@state()
@storage({
storage: "sessionStorage",
key: "lovelace-resources-table-search",

View File

@ -133,6 +133,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
@state() private _filteredScenes?: string[] | null;
@state()
@storage({
storage: "sessionStorage",
key: "scene-table-search",
@ -141,6 +142,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
})
private _filter = "";
@state()
@storage({
storage: "sessionStorage",
key: "scene-table-filters-full",

View File

@ -105,6 +105,7 @@ export class HaScriptEditor extends SubscribeMixin(
@state() private _readOnly = false;
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
@transform<EntityRegistryEntry[], EntityRegistryEntry>({
transformer: function (this: HaScriptEditor, value) {

View File

@ -138,6 +138,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
@state() private _filteredScripts?: string[] | null;
@state()
@storage({
storage: "sessionStorage",
key: "script-table-search",
@ -146,6 +147,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
})
private _filter = "";
@state()
@storage({
storage: "sessionStorage",
key: "script-table-filters-full",

View File

@ -62,6 +62,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
return this.hass.auth.external?.config.canWriteTag;
}
@state()
@storage({
storage: "sessionStorage",
key: "tags-table-search",

View File

@ -76,6 +76,7 @@ export class VoiceAssistantsExpose extends LitElement {
@state() private _extEntities?: Record<string, ExtEntityRegistryEntry>;
@state()
@storage({
storage: "sessionStorage",
key: "voice-expose-table-search",

View File

@ -52,6 +52,7 @@ class HaPanelDevAction extends LitElement {
private _yamlValid = true;
@state()
@storage({
key: "panel-dev-action-state-service-data",
state: true,
@ -59,6 +60,7 @@ class HaPanelDevAction extends LitElement {
})
private _serviceData?: ServiceAction = { action: "", target: {}, data: {} };
@state()
@storage({
key: "panel-dev-action-state-yaml-mode",
state: true,

View File

@ -33,6 +33,7 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
@state() supportedLanguages?: string[];
@state()
@storage({
key: "assist_debug_language",
state: true,

View File

@ -62,6 +62,7 @@ class HaPanelDevState extends LitElement {
@state() private _validJSON = true;
@state()
@storage({
key: "devToolsShowAttributes",
state: true,

View File

@ -63,6 +63,7 @@ class HaPanelHistory extends LitElement {
@state() private _endDate: Date;
@state()
@storage({
key: "historyPickedValue",
state: true,

View File

@ -39,6 +39,7 @@ export class HaPanelLogbook extends LitElement {
@state()
private _showBack?: boolean;
@state()
@storage({
key: "logbookPickedValue",
state: true,

View File

@ -62,6 +62,7 @@ export class HuiEnergyDevicesDetailGraphCard
@state() private _compareEnd?: Date;
@state()
@storage({
key: "energy-devices-hidden-stats",
state: true,

View File

@ -86,6 +86,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
@state() private _config?: ButtonCardConfig;
@state()
@consume<any>({ context: statesContext, subscribe: true })
@transform({
transformer: function (this: HuiButtonCard, value: HassEntities) {
@ -111,6 +112,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
@consume({ context: configContext, subscribe: true })
_hassConfig!: HassConfig;
@state()
@consume<any>({ context: entitiesContext, subscribe: true })
@transform<HomeAssistant["entities"], EntityRegistryDisplayEntry>({
transformer: function (this: HuiButtonCard, value) {

View File

@ -43,6 +43,7 @@ export class HuiBadgePicker extends LitElement {
@property({ attribute: false }) public suggestedBadges?: string[];
@state()
@storage({
key: "dashboardBadgeClipboard",
state: true,

View File

@ -42,6 +42,7 @@ export class HuiCardPicker extends LitElement {
@property({ attribute: false }) public suggestedCards?: string[];
@state()
@storage({
key: "dashboardCardClipboard",
state: true,

View File

@ -64,6 +64,7 @@ class PanelMediaBrowser extends LitElement {
@state() _currentItem?: MediaPlayerItem;
@state()
@storage({
key: "mediaBrowserPreferredLayout",
state: true,
@ -78,6 +79,7 @@ class PanelMediaBrowser extends LitElement {
},
];
@state()
@storage({
key: "mediaBrowseEntityId",
state: true,

View File

@ -9,7 +9,7 @@ import {
} from "@mdi/js";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { storage } from "../../common/decorators/storage";
@ -55,6 +55,7 @@ class PanelTodo extends LitElement {
@property({ type: Boolean, reflect: true }) public mobile = false;
@state()
@storage({
key: "selectedTodoEntity",
state: true,