From 46bb4ee96793ad471d7e463f0c49f75b6a32c098 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 5 Aug 2024 21:59:49 +0200 Subject: [PATCH] Add 2024.7 backward compatibility (#1488) --- package.json | 2 + .../alarm-control-panel-card-editor.ts | 54 ++++++++++++------- .../chips-card/chips/action-chip-editor.ts | 14 +++-- .../chips/alarm-control-panel-chip-editor.ts | 14 +++-- .../chips-card/chips/weather-chip-editor.ts | 14 +++-- src/cards/person-card/person-card-editor.ts | 14 +++-- src/cards/select-card/select-card-editor.ts | 14 +++-- src/cards/update-card/update-card-editor.ts | 14 +++-- src/shared/config/actions-config.ts | 11 +++- src/utils/base-element.ts | 15 +++++- 10 files changed, 114 insertions(+), 52 deletions(-) diff --git a/package.json b/package.json index dbfca70d..8c38c5da 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "start": "rollup -c --watch --bundleConfigAsCjs", "build": "rollup -c --bundleConfigAsCjs", "format": "prettier --write .", + "start:hass-stable": "docker run --rm -p8123:8123 -v ${PWD}/.hass_dev:/config homeassistant/home-assistant:stable", + "start:hass-stable-cmd": "docker run --rm -p8123:8123 -v %cd%/.hass_dev:/config homeassistant/home-assistant:stable", "start:hass": "docker run --rm -p8123:8123 -v ${PWD}/.hass_dev:/config homeassistant/home-assistant:beta", "start:hass-cmd": "docker run --rm -p8123:8123 -v %cd%/.hass_dev:/config homeassistant/home-assistant:beta", "start:hass-dev": "docker run --rm -p8123:8123 -v ${PWD}/.hass_dev:/config homeassistant/home-assistant:dev", diff --git a/src/cards/alarm-control-panel-card/alarm-control-panel-card-editor.ts b/src/cards/alarm-control-panel-card/alarm-control-panel-card-editor.ts index 1f52cd59..240b9b3e 100644 --- a/src/cards/alarm-control-panel-card/alarm-control-panel-card-editor.ts +++ b/src/cards/alarm-control-panel-card/alarm-control-panel-card-editor.ts @@ -2,7 +2,12 @@ import { html, nothing } from "lit"; import { customElement, state } from "lit/decorators.js"; import memoizeOne from "memoize-one"; import { assert } from "superstruct"; -import { LocalizeFunc, LovelaceCardEditor, fireEvent } from "../../ha"; +import { + LocalizeFunc, + LovelaceCardEditor, + atLeastHaVersion, + fireEvent, +} from "../../ha"; import setupCustomlocalize from "../../localize"; import { computeActionsFormSchema } from "../../shared/config/actions-config"; import { APPEARANCE_FORM_SCHEMA } from "../../shared/config/appearance-config"; @@ -37,24 +42,32 @@ const states = [ "armed_custom_bypass", ]; -const computeSchema = memoizeOne((localize: LocalizeFunc): HaFormSchema[] => [ - { - name: "entity", - selector: { entity: { domain: ALARM_CONTROl_PANEL_ENTITY_DOMAINS } }, - }, - { name: "name", selector: { text: {} } }, - { name: "icon", selector: { icon: {} }, context: { icon_entity: "entity" } }, - ...APPEARANCE_FORM_SCHEMA, - { - type: "multi_select", - name: "states", - options: states.map((state) => [ - state, - localize(`ui.card.alarm_control_panel.${state.replace("armed", "arm")}`), - ]) as [string, string][], - }, - ...computeActionsFormSchema(actions), -]); +const computeSchema = memoizeOne( + (localize: LocalizeFunc, useCallService: boolean): HaFormSchema[] => [ + { + name: "entity", + selector: { entity: { domain: ALARM_CONTROl_PANEL_ENTITY_DOMAINS } }, + }, + { name: "name", selector: { text: {} } }, + { + name: "icon", + selector: { icon: {} }, + context: { icon_entity: "entity" }, + }, + ...APPEARANCE_FORM_SCHEMA, + { + type: "multi_select", + name: "states", + options: states.map((state) => [ + state, + localize( + `ui.card.alarm_control_panel.${state.replace("armed", "arm")}` + ), + ]) as [string, string][], + }, + ...computeActionsFormSchema(actions, useCallService), + ] +); @customElement(ALARM_CONTROl_PANEL_CARD_EDITOR_NAME) export class SwitchCardEditor @@ -78,7 +91,8 @@ export class SwitchCardEditor return nothing; } - const schema = computeSchema(this.hass!.localize); + const useCallService = !atLeastHaVersion(this.hass.config.version, 2024, 8); + const schema = computeSchema(this.hass!.localize, useCallService); return html` [ { type: "grid", name: "", @@ -31,8 +32,8 @@ const SCHEMA: HaFormSchema[] = [ { name: "icon_color", selector: { mush_color: {} } }, ], }, - ...computeActionsFormSchema(actions), -]; + ...computeActionsFormSchema(actions, useCallService), +]); @customElement(computeChipEditorComponentName("action")) export class EntityChipEditor extends LitElement implements LovelaceChipEditor { @@ -60,11 +61,14 @@ export class EntityChipEditor extends LitElement implements LovelaceChipEditor { return nothing; } + const useCallService = !atLeastHaVersion(this.hass.config.version, 2024, 8); + const schema = computeSchema(useCallService); + return html` diff --git a/src/cards/chips-card/chips/alarm-control-panel-chip-editor.ts b/src/cards/chips-card/chips/alarm-control-panel-chip-editor.ts index df5ee9fe..37fc1c5d 100644 --- a/src/cards/chips-card/chips/alarm-control-panel-chip-editor.ts +++ b/src/cards/chips-card/chips/alarm-control-panel-chip-editor.ts @@ -1,6 +1,6 @@ import { html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; -import { fireEvent, HomeAssistant } from "../../../ha"; +import { atLeastHaVersion, fireEvent, HomeAssistant } from "../../../ha"; import setupCustomlocalize from "../../../localize"; import { computeActionsFormSchema } from "../../../shared/config/actions-config"; import { GENERIC_LABELS } from "../../../utils/form/generic-fields"; @@ -10,6 +10,7 @@ import { computeChipEditorComponentName } from "../../../utils/lovelace/chip/chi import { AlarmControlPanelChipConfig } from "../../../utils/lovelace/chip/types"; import { LovelaceChipEditor } from "../../../utils/lovelace/types"; import { ALARM_CONTROl_PANEL_ENTITY_DOMAINS } from "../../alarm-control-panel-card/const"; +import memoizeOne from "memoize-one"; const actions: UiAction[] = [ "more-info", @@ -20,7 +21,7 @@ const actions: UiAction[] = [ "none", ]; -const SCHEMA: HaFormSchema[] = [ +const computeSchema = memoizeOne((useCallService: boolean): HaFormSchema[] => [ { name: "entity", selector: { entity: { domain: ALARM_CONTROl_PANEL_ENTITY_DOMAINS } }, @@ -34,8 +35,8 @@ const SCHEMA: HaFormSchema[] = [ ], }, { name: "icon", selector: { icon: {} }, context: { icon_entity: "entity" } }, - ...computeActionsFormSchema(actions), -]; + ...computeActionsFormSchema(actions, useCallService), +]); @customElement(computeChipEditorComponentName("alarm-control-panel")) export class AlarmControlPanelChipEditor @@ -66,11 +67,14 @@ export class AlarmControlPanelChipEditor return nothing; } + const useCallService = !atLeastHaVersion(this.hass.config.version, 2024, 8); + const schema = computeSchema(useCallService); + return html` diff --git a/src/cards/chips-card/chips/weather-chip-editor.ts b/src/cards/chips-card/chips/weather-chip-editor.ts index 4f8afe96..49f0c1ec 100644 --- a/src/cards/chips-card/chips/weather-chip-editor.ts +++ b/src/cards/chips-card/chips/weather-chip-editor.ts @@ -1,6 +1,6 @@ import { html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; -import { fireEvent, HomeAssistant } from "../../../ha"; +import { atLeastHaVersion, fireEvent, HomeAssistant } from "../../../ha"; import setupCustomlocalize from "../../../localize"; import { computeActionsFormSchema } from "../../../shared/config/actions-config"; import { GENERIC_LABELS } from "../../../utils/form/generic-fields"; @@ -9,6 +9,7 @@ import { UiAction } from "../../../utils/form/ha-selector"; import { computeChipEditorComponentName } from "../../../utils/lovelace/chip/chip-element"; import { WeatherChipConfig } from "../../../utils/lovelace/chip/types"; import { LovelaceChipEditor } from "../../../utils/lovelace/types"; +import memoizeOne from "memoize-one"; const WEATHER_ENTITY_DOMAINS = ["weather"]; const WEATHER_LABELS = ["show_conditions", "show_temperature"]; @@ -22,7 +23,7 @@ const actions: UiAction[] = [ "none", ]; -const SCHEMA: HaFormSchema[] = [ +const computeSchema = memoizeOne((useCallService: boolean): HaFormSchema[] => [ { name: "entity", selector: { entity: { domain: WEATHER_ENTITY_DOMAINS } } }, { type: "grid", @@ -32,8 +33,8 @@ const SCHEMA: HaFormSchema[] = [ { name: "show_temperature", selector: { boolean: {} } }, ], }, - ...computeActionsFormSchema(actions), -]; + ...computeActionsFormSchema(actions, useCallService), +]); @customElement(computeChipEditorComponentName("weather")) export class WeatherChipEditor @@ -67,11 +68,14 @@ export class WeatherChipEditor return nothing; } + const useCallService = !atLeastHaVersion(this.hass.config.version, 2024, 8); + const schema = computeSchema(useCallService); + return html` diff --git a/src/cards/person-card/person-card-editor.ts b/src/cards/person-card/person-card-editor.ts index 6c9447d7..8a26f872 100644 --- a/src/cards/person-card/person-card-editor.ts +++ b/src/cards/person-card/person-card-editor.ts @@ -1,7 +1,7 @@ import { html, nothing } from "lit"; import { customElement, state } from "lit/decorators.js"; import { assert } from "superstruct"; -import { LovelaceCardEditor, fireEvent } from "../../ha"; +import { LovelaceCardEditor, atLeastHaVersion, fireEvent } from "../../ha"; import setupCustomlocalize from "../../localize"; import { computeActionsFormSchema } from "../../shared/config/actions-config"; import { APPEARANCE_FORM_SCHEMA } from "../../shared/config/appearance-config"; @@ -12,6 +12,7 @@ import { UiAction } from "../../utils/form/ha-selector"; import { loadHaComponents } from "../../utils/loader"; import { PERSON_CARD_EDITOR_NAME, PERSON_ENTITY_DOMAINS } from "./const"; import { PersonCardConfig, personCardConfigStruct } from "./person-card-config"; +import memoizeOne from "memoize-one"; const actions: UiAction[] = [ "more-info", @@ -22,13 +23,13 @@ const actions: UiAction[] = [ "none", ]; -const SCHEMA: HaFormSchema[] = [ +const computeSchema = memoizeOne((useCallService: boolean): HaFormSchema[] => [ { name: "entity", selector: { entity: { domain: PERSON_ENTITY_DOMAINS } } }, { name: "name", selector: { text: {} } }, { name: "icon", selector: { icon: {} }, context: { icon_entity: "entity" } }, ...APPEARANCE_FORM_SCHEMA, - ...computeActionsFormSchema(actions), -]; + ...computeActionsFormSchema(actions, useCallService), +]); @customElement(PERSON_CARD_EDITOR_NAME) export class SwitchCardEditor @@ -63,11 +64,14 @@ export class SwitchCardEditor return nothing; } + const useCallService = !atLeastHaVersion(this.hass.config.version, 2024, 8); + const schema = computeSchema(useCallService); + return html` diff --git a/src/cards/select-card/select-card-editor.ts b/src/cards/select-card/select-card-editor.ts index 51416fa2..19652611 100644 --- a/src/cards/select-card/select-card-editor.ts +++ b/src/cards/select-card/select-card-editor.ts @@ -1,7 +1,7 @@ import { html, nothing } from "lit"; import { customElement, state } from "lit/decorators.js"; import { assert } from "superstruct"; -import { LovelaceCardEditor, fireEvent } from "../../ha"; +import { LovelaceCardEditor, atLeastHaVersion, fireEvent } from "../../ha"; import setupCustomlocalize from "../../localize"; import { computeActionsFormSchema } from "../../shared/config/actions-config"; import { APPEARANCE_FORM_SCHEMA } from "../../shared/config/appearance-config"; @@ -12,6 +12,7 @@ import { UiAction } from "../../utils/form/ha-selector"; import { loadHaComponents } from "../../utils/loader"; import { SELECT_CARD_EDITOR_NAME, SELECT_ENTITY_DOMAINS } from "./const"; import { SelectCardConfig, selectCardConfigStruct } from "./select-card-config"; +import memoizeOne from "memoize-one"; const actions: UiAction[] = [ "more-info", @@ -22,7 +23,7 @@ const actions: UiAction[] = [ "none", ]; -const SCHEMA: HaFormSchema[] = [ +const computeSchema = memoizeOne((useCallService: boolean): HaFormSchema[] => [ { name: "entity", selector: { entity: { domain: SELECT_ENTITY_DOMAINS } } }, { name: "name", selector: { text: {} } }, { @@ -38,8 +39,8 @@ const SCHEMA: HaFormSchema[] = [ ], }, ...APPEARANCE_FORM_SCHEMA, - ...computeActionsFormSchema(actions), -]; + ...computeActionsFormSchema(actions, useCallService), +]); @customElement(SELECT_CARD_EDITOR_NAME) export class SelectCardEditor @@ -74,11 +75,14 @@ export class SelectCardEditor return nothing; } + const useCallService = !atLeastHaVersion(this.hass.config.version, 2024, 8); + const schema = computeSchema(useCallService); + return html` diff --git a/src/cards/update-card/update-card-editor.ts b/src/cards/update-card/update-card-editor.ts index 1abd8ec6..67c8df72 100644 --- a/src/cards/update-card/update-card-editor.ts +++ b/src/cards/update-card/update-card-editor.ts @@ -1,7 +1,7 @@ import { html, nothing } from "lit"; import { customElement, state } from "lit/decorators.js"; import { assert } from "superstruct"; -import { LovelaceCardEditor, fireEvent } from "../../ha"; +import { LovelaceCardEditor, atLeastHaVersion, fireEvent } from "../../ha"; import setupCustomlocalize from "../../localize"; import { computeActionsFormSchema } from "../../shared/config/actions-config"; import { APPEARANCE_FORM_SCHEMA } from "../../shared/config/appearance-config"; @@ -12,6 +12,7 @@ import { UiAction } from "../../utils/form/ha-selector"; import { loadHaComponents } from "../../utils/loader"; import { UPDATE_CARD_EDITOR_NAME, UPDATE_ENTITY_DOMAINS } from "./const"; import { UpdateCardConfig, updateCardConfigStruct } from "./update-card-config"; +import memoizeOne from "memoize-one"; const UPDATE_LABELS = ["show_buttons_control"]; @@ -24,7 +25,7 @@ const actions: UiAction[] = [ "none", ]; -const SCHEMA: HaFormSchema[] = [ +const computeSchema = memoizeOne((useCallService: boolean): HaFormSchema[] => [ { name: "entity", selector: { entity: { domain: UPDATE_ENTITY_DOMAINS } } }, { name: "name", selector: { text: {} } }, { name: "icon", selector: { icon: {} }, context: { icon_entity: "entity" } }, @@ -37,8 +38,8 @@ const SCHEMA: HaFormSchema[] = [ { name: "collapsible_controls", selector: { boolean: {} } }, ], }, - ...computeActionsFormSchema(actions), -]; + ...computeActionsFormSchema(actions, useCallService), +]); @customElement(UPDATE_CARD_EDITOR_NAME) export class UpdateCardEditor @@ -76,11 +77,14 @@ export class UpdateCardEditor return nothing; } + const useCallService = !atLeastHaVersion(this.hass.config.version, 2024, 8); + const schema = computeSchema(useCallService); + return html` diff --git a/src/shared/config/actions-config.ts b/src/shared/config/actions-config.ts index d2323ed8..4db0928e 100644 --- a/src/shared/config/actions-config.ts +++ b/src/shared/config/actions-config.ts @@ -16,8 +16,17 @@ export type ActionsSharedConfig = { }; export const computeActionsFormSchema = ( - actions?: UiAction[] + actions?: UiAction[], + useCallService?: boolean ): HaFormSchema[] => { + if (useCallService && actions) { + actions = actions.map((action) => { + if (action === "perform-action") { + return "call-service"; + } + return action; + }); + } return [ { name: "tap_action", diff --git a/src/utils/base-element.ts b/src/utils/base-element.ts index 2b469a14..139adc8d 100644 --- a/src/utils/base-element.ts +++ b/src/utils/base-element.ts @@ -1,6 +1,6 @@ import { css, CSSResultGroup, LitElement, PropertyValues } from "lit"; import { property } from "lit/decorators.js"; -import { HomeAssistant } from "../ha"; +import { atLeastHaVersion, HomeAssistant } from "../ha"; import "../shared/badge-icon"; import "../shared/card"; import "../shared/shape-avatar"; @@ -18,6 +18,13 @@ export function computeDarkMode(hass?: HomeAssistant): boolean { export class MushroomBaseElement extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; + protected firstUpdated(_changedProperties: PropertyValues): void { + this.toggleAttribute( + "pre-2024-8", + !atLeastHaVersion(this.hass.config.version, 2024, 8) + ); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); if (changedProps.has("hass") && this.hass) { @@ -43,6 +50,12 @@ export class MushroomBaseElement extends LitElement { ${themeColorCss} ${themeVariables} } + :host([pre-2024-8]) { + --spacing: var(--mush-spacing, 12px); + --control-height: var(--mush-control-height, 40px); + --control-spacing: var(--mush-spacing, 12px); + --icon-size: var(--mush-icon-size, 40px); + } `, ]; }