From a16cae0671c744b4ea87ec90a04ecbff918a7ca6 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 26 Jun 2024 23:09:42 +0200 Subject: [PATCH 1/4] 20240626.1 (#21179) * Fix undefined value in search (#21175) * Fix hass object in nested hui-card (#21178) * Bumped version to 20240626.1 --- hassio/src/components/hassio-filter-addons.ts | 3 ++- pyproject.toml | 2 +- src/common/string/strip-diacritics.ts | 2 +- .../add-automation-element-dialog.ts | 5 ++-- .../integrations/dialog-add-integration.ts | 3 ++- .../ha-config-integrations-dashboard.ts | 25 ++++++++++--------- src/panels/lovelace/cards/hui-card.ts | 2 ++ .../editor/card-editor/hui-card-picker.ts | 3 ++- src/util/fuse.ts | 12 +++++++++ 9 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 src/util/fuse.ts diff --git a/hassio/src/components/hassio-filter-addons.ts b/hassio/src/components/hassio-filter-addons.ts index cb72ab3a52..1970aa5495 100644 --- a/hassio/src/components/hassio-filter-addons.ts +++ b/hassio/src/components/hassio-filter-addons.ts @@ -2,6 +2,7 @@ import type { IFuseOptions } from "fuse.js"; import Fuse from "fuse.js"; import { stripDiacritics } from "../../../src/common/string/strip-diacritics"; import { StoreAddon } from "../../../src/data/supervisor/store"; +import { getStripDiacriticsFn } from "../../../src/util/fuse"; export function filterAndSort(addons: StoreAddon[], filter: string) { const options: IFuseOptions = { @@ -9,7 +10,7 @@ export function filterAndSort(addons: StoreAddon[], filter: string) { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), + getFn: getStripDiacriticsFn, }; const fuse = new Fuse(addons, options); return fuse.search(stripDiacritics(filter)).map((result) => result.item); diff --git a/pyproject.toml b/pyproject.toml index e2c30d045b..2a2ab98c32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240626.0" +version = "20240626.1" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/common/string/strip-diacritics.ts b/src/common/string/strip-diacritics.ts index a82ddf2c45..6a704d86e3 100644 --- a/src/common/string/strip-diacritics.ts +++ b/src/common/string/strip-diacritics.ts @@ -1,2 +1,2 @@ -export const stripDiacritics = (str) => +export const stripDiacritics = (str: string) => str.normalize("NFD").replace(/[\u0300-\u036F]/g, ""); diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index 6f75232f52..a18822216b 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -18,6 +18,7 @@ import memoizeOne from "memoize-one"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; import { stringCompare } from "../../../common/string/compare"; +import { stripDiacritics } from "../../../common/string/strip-diacritics"; import { LocalizeFunc } from "../../../common/translations/localize"; import { deepEqual } from "../../../common/util/deep-equal"; import "../../../components/ha-dialog"; @@ -50,11 +51,11 @@ import { TRIGGER_GROUPS, TRIGGER_ICONS } from "../../../data/trigger"; import { HassDialog } from "../../../dialogs/make-dialog-manager"; import { haStyle, haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; +import { getStripDiacriticsFn } from "../../../util/fuse"; import { AddAutomationElementDialogParams, PASTE_VALUE, } from "./show-add-automation-element-dialog"; -import { stripDiacritics } from "../../../common/string/strip-diacritics"; const TYPES = { trigger: { groups: TRIGGER_GROUPS, icons: TRIGGER_ICONS }, @@ -209,7 +210,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), + getFn: getStripDiacriticsFn, }; const fuse = new Fuse(items, options); return fuse.search(stripDiacritics(filter)).map((result) => result.item); diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts index 004ac0c611..e94008727d 100644 --- a/src/panels/config/integrations/dialog-add-integration.ts +++ b/src/panels/config/integrations/dialog-add-integration.ts @@ -56,6 +56,7 @@ import { } from "./show-add-integration-dialog"; import { getConfigEntries } from "../../../data/config_entries"; import { stripDiacritics } from "../../../common/string/strip-diacritics"; +import { getStripDiacriticsFn } from "../../../util/fuse"; export interface IntegrationListItem { name: string; @@ -256,7 +257,7 @@ class AddIntegrationDialog extends LitElement { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), + getFn: getStripDiacriticsFn, }; const helpers = Object.entries(h).map(([domain, integration]) => ({ domain, diff --git a/src/panels/config/integrations/ha-config-integrations-dashboard.ts b/src/panels/config/integrations/ha-config-integrations-dashboard.ts index 48987048d8..8c1dacbf3e 100644 --- a/src/panels/config/integrations/ha-config-integrations-dashboard.ts +++ b/src/panels/config/integrations/ha-config-integrations-dashboard.ts @@ -1,25 +1,27 @@ import { ActionDetail } from "@material/mwc-list"; import { mdiFilterVariant, mdiPlus } from "@mdi/js"; -import Fuse from "fuse.js"; import type { IFuseOptions } from "fuse.js"; +import Fuse from "fuse.js"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import { - css, CSSResultGroup, - html, LitElement, - nothing, PropertyValues, + css, + html, + nothing, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { - protocolIntegrationPicked, PROTOCOL_INTEGRATIONS, + protocolIntegrationPicked, } from "../../../common/integrations/protocolIntegrationPicked"; import { navigate } from "../../../common/navigate"; +import { caseInsensitiveStringCompare } from "../../../common/string/compare"; +import { stripDiacritics } from "../../../common/string/strip-diacritics"; import { extractSearchParam } from "../../../common/url/search-params"; import { nextRender } from "../../../common/util/render-status"; import "../../../components/ha-button-menu"; @@ -29,6 +31,7 @@ import "../../../components/ha-fab"; import "../../../components/ha-icon-button"; import "../../../components/ha-svg-icon"; import "../../../components/search-input"; +import "../../../components/search-input-outlined"; import { ConfigEntry, getConfigEntries } from "../../../data/config_entries"; import { getConfigFlowInProgressCollection } from "../../../data/config_flow"; import { fetchDiagnosticHandlers } from "../../../data/diagnostics"; @@ -37,11 +40,11 @@ import { subscribeEntityRegistry, } from "../../../data/entity_registry"; import { + IntegrationLogInfo, + IntegrationManifest, domainToName, fetchIntegrationManifest, fetchIntegrationManifests, - IntegrationLogInfo, - IntegrationManifest, subscribeLogInfo, } from "../../../data/integration"; import { @@ -59,19 +62,17 @@ import "../../../layouts/hass-tabs-subpage"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant, Route } from "../../../types"; +import { getStripDiacriticsFn } from "../../../util/fuse"; import { configSections } from "../ha-panel-config"; import { isHelperDomain } from "../helpers/const"; import "./ha-config-flow-card"; import { DataEntryFlowProgressExtended } from "./ha-config-integrations"; +import "./ha-disabled-config-entry-card"; import "./ha-ignored-config-entry-card"; import "./ha-integration-card"; import type { HaIntegrationCard } from "./ha-integration-card"; import "./ha-integration-overflow-menu"; import { showAddIntegrationDialog } from "./show-add-integration-dialog"; -import "./ha-disabled-config-entry-card"; -import { caseInsensitiveStringCompare } from "../../../common/string/compare"; -import "../../../components/search-input-outlined"; -import { stripDiacritics } from "../../../common/string/strip-diacritics"; export interface ConfigEntryExtended extends ConfigEntry { localized_domain_name?: string; @@ -209,7 +210,7 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), + getFn: getStripDiacriticsFn, }; const fuse = new Fuse(configEntriesInProgress, options); filteredEntries = fuse diff --git a/src/panels/lovelace/cards/hui-card.ts b/src/panels/lovelace/cards/hui-card.ts index e8091f2b87..a892d4764d 100644 --- a/src/panels/lovelace/cards/hui-card.ts +++ b/src/panels/lovelace/cards/hui-card.ts @@ -105,6 +105,8 @@ export class HuiCard extends ReactiveElement { "ll-upgrade", (ev: Event) => { ev.stopPropagation(); + element.hass = this.hass; + element.preview = this.preview; fireEvent(this, "card-updated"); }, { once: true } diff --git a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts index 65d8d94bdd..3537955479 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -29,6 +29,7 @@ import { getCustomCardEntry, } from "../../../../data/lovelace_custom_cards"; import type { HomeAssistant } from "../../../../types"; +import { getStripDiacriticsFn } from "../../../../util/fuse"; import { calcUnusedEntities, computeUsedEntities, @@ -87,7 +88,7 @@ export class HuiCardPicker extends LitElement { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), + getFn: getStripDiacriticsFn, }; const fuse = new Fuse(cards, options); cards = fuse.search(stripDiacritics(filter)).map((result) => result.item); diff --git a/src/util/fuse.ts b/src/util/fuse.ts new file mode 100644 index 0000000000..56157d7001 --- /dev/null +++ b/src/util/fuse.ts @@ -0,0 +1,12 @@ +import Fuse from "fuse.js"; +import { stripDiacritics } from "../common/string/strip-diacritics"; + +type GetFn = typeof Fuse.config.getFn; + +export const getStripDiacriticsFn: GetFn = (obj, path) => { + const value = Fuse.config.getFn(obj, path); + if (Array.isArray(value)) { + return value.map((v) => stripDiacritics(v ?? "")); + } + return stripDiacritics((value as string | undefined) ?? ""); +}; From 530745d20d9a8c3b202a4cf790e9313e7ad99cf5 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 26 Jun 2024 23:18:27 +0200 Subject: [PATCH 2/4] Revert "20240626.1" (#21180) Revert "20240626.1 (#21179)" This reverts commit a16cae0671c744b4ea87ec90a04ecbff918a7ca6. --- hassio/src/components/hassio-filter-addons.ts | 3 +-- pyproject.toml | 2 +- src/common/string/strip-diacritics.ts | 2 +- .../add-automation-element-dialog.ts | 5 ++-- .../integrations/dialog-add-integration.ts | 3 +-- .../ha-config-integrations-dashboard.ts | 25 +++++++++---------- src/panels/lovelace/cards/hui-card.ts | 2 -- .../editor/card-editor/hui-card-picker.ts | 3 +-- src/util/fuse.ts | 12 --------- 9 files changed, 19 insertions(+), 38 deletions(-) delete mode 100644 src/util/fuse.ts diff --git a/hassio/src/components/hassio-filter-addons.ts b/hassio/src/components/hassio-filter-addons.ts index 1970aa5495..cb72ab3a52 100644 --- a/hassio/src/components/hassio-filter-addons.ts +++ b/hassio/src/components/hassio-filter-addons.ts @@ -2,7 +2,6 @@ import type { IFuseOptions } from "fuse.js"; import Fuse from "fuse.js"; import { stripDiacritics } from "../../../src/common/string/strip-diacritics"; import { StoreAddon } from "../../../src/data/supervisor/store"; -import { getStripDiacriticsFn } from "../../../src/util/fuse"; export function filterAndSort(addons: StoreAddon[], filter: string) { const options: IFuseOptions = { @@ -10,7 +9,7 @@ export function filterAndSort(addons: StoreAddon[], filter: string) { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: getStripDiacriticsFn, + getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), }; const fuse = new Fuse(addons, options); return fuse.search(stripDiacritics(filter)).map((result) => result.item); diff --git a/pyproject.toml b/pyproject.toml index 2a2ab98c32..e2c30d045b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240626.1" +version = "20240626.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/common/string/strip-diacritics.ts b/src/common/string/strip-diacritics.ts index 6a704d86e3..a82ddf2c45 100644 --- a/src/common/string/strip-diacritics.ts +++ b/src/common/string/strip-diacritics.ts @@ -1,2 +1,2 @@ -export const stripDiacritics = (str: string) => +export const stripDiacritics = (str) => str.normalize("NFD").replace(/[\u0300-\u036F]/g, ""); diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index a18822216b..6f75232f52 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -18,7 +18,6 @@ import memoizeOne from "memoize-one"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; import { stringCompare } from "../../../common/string/compare"; -import { stripDiacritics } from "../../../common/string/strip-diacritics"; import { LocalizeFunc } from "../../../common/translations/localize"; import { deepEqual } from "../../../common/util/deep-equal"; import "../../../components/ha-dialog"; @@ -51,11 +50,11 @@ import { TRIGGER_GROUPS, TRIGGER_ICONS } from "../../../data/trigger"; import { HassDialog } from "../../../dialogs/make-dialog-manager"; import { haStyle, haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; -import { getStripDiacriticsFn } from "../../../util/fuse"; import { AddAutomationElementDialogParams, PASTE_VALUE, } from "./show-add-automation-element-dialog"; +import { stripDiacritics } from "../../../common/string/strip-diacritics"; const TYPES = { trigger: { groups: TRIGGER_GROUPS, icons: TRIGGER_ICONS }, @@ -210,7 +209,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: getStripDiacriticsFn, + getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), }; const fuse = new Fuse(items, options); return fuse.search(stripDiacritics(filter)).map((result) => result.item); diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts index e94008727d..004ac0c611 100644 --- a/src/panels/config/integrations/dialog-add-integration.ts +++ b/src/panels/config/integrations/dialog-add-integration.ts @@ -56,7 +56,6 @@ import { } from "./show-add-integration-dialog"; import { getConfigEntries } from "../../../data/config_entries"; import { stripDiacritics } from "../../../common/string/strip-diacritics"; -import { getStripDiacriticsFn } from "../../../util/fuse"; export interface IntegrationListItem { name: string; @@ -257,7 +256,7 @@ class AddIntegrationDialog extends LitElement { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: getStripDiacriticsFn, + getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), }; const helpers = Object.entries(h).map(([domain, integration]) => ({ domain, diff --git a/src/panels/config/integrations/ha-config-integrations-dashboard.ts b/src/panels/config/integrations/ha-config-integrations-dashboard.ts index 8c1dacbf3e..48987048d8 100644 --- a/src/panels/config/integrations/ha-config-integrations-dashboard.ts +++ b/src/panels/config/integrations/ha-config-integrations-dashboard.ts @@ -1,27 +1,25 @@ import { ActionDetail } from "@material/mwc-list"; import { mdiFilterVariant, mdiPlus } from "@mdi/js"; -import type { IFuseOptions } from "fuse.js"; import Fuse from "fuse.js"; +import type { IFuseOptions } from "fuse.js"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import { - CSSResultGroup, - LitElement, - PropertyValues, css, + CSSResultGroup, html, + LitElement, nothing, + PropertyValues, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { - PROTOCOL_INTEGRATIONS, protocolIntegrationPicked, + PROTOCOL_INTEGRATIONS, } from "../../../common/integrations/protocolIntegrationPicked"; import { navigate } from "../../../common/navigate"; -import { caseInsensitiveStringCompare } from "../../../common/string/compare"; -import { stripDiacritics } from "../../../common/string/strip-diacritics"; import { extractSearchParam } from "../../../common/url/search-params"; import { nextRender } from "../../../common/util/render-status"; import "../../../components/ha-button-menu"; @@ -31,7 +29,6 @@ import "../../../components/ha-fab"; import "../../../components/ha-icon-button"; import "../../../components/ha-svg-icon"; import "../../../components/search-input"; -import "../../../components/search-input-outlined"; import { ConfigEntry, getConfigEntries } from "../../../data/config_entries"; import { getConfigFlowInProgressCollection } from "../../../data/config_flow"; import { fetchDiagnosticHandlers } from "../../../data/diagnostics"; @@ -40,11 +37,11 @@ import { subscribeEntityRegistry, } from "../../../data/entity_registry"; import { - IntegrationLogInfo, - IntegrationManifest, domainToName, fetchIntegrationManifest, fetchIntegrationManifests, + IntegrationLogInfo, + IntegrationManifest, subscribeLogInfo, } from "../../../data/integration"; import { @@ -62,17 +59,19 @@ import "../../../layouts/hass-tabs-subpage"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant, Route } from "../../../types"; -import { getStripDiacriticsFn } from "../../../util/fuse"; import { configSections } from "../ha-panel-config"; import { isHelperDomain } from "../helpers/const"; import "./ha-config-flow-card"; import { DataEntryFlowProgressExtended } from "./ha-config-integrations"; -import "./ha-disabled-config-entry-card"; import "./ha-ignored-config-entry-card"; import "./ha-integration-card"; import type { HaIntegrationCard } from "./ha-integration-card"; import "./ha-integration-overflow-menu"; import { showAddIntegrationDialog } from "./show-add-integration-dialog"; +import "./ha-disabled-config-entry-card"; +import { caseInsensitiveStringCompare } from "../../../common/string/compare"; +import "../../../components/search-input-outlined"; +import { stripDiacritics } from "../../../common/string/strip-diacritics"; export interface ConfigEntryExtended extends ConfigEntry { localized_domain_name?: string; @@ -210,7 +209,7 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: getStripDiacriticsFn, + getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), }; const fuse = new Fuse(configEntriesInProgress, options); filteredEntries = fuse diff --git a/src/panels/lovelace/cards/hui-card.ts b/src/panels/lovelace/cards/hui-card.ts index a892d4764d..e8091f2b87 100644 --- a/src/panels/lovelace/cards/hui-card.ts +++ b/src/panels/lovelace/cards/hui-card.ts @@ -105,8 +105,6 @@ export class HuiCard extends ReactiveElement { "ll-upgrade", (ev: Event) => { ev.stopPropagation(); - element.hass = this.hass; - element.preview = this.preview; fireEvent(this, "card-updated"); }, { once: true } diff --git a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts index 3537955479..65d8d94bdd 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -29,7 +29,6 @@ import { getCustomCardEntry, } from "../../../../data/lovelace_custom_cards"; import type { HomeAssistant } from "../../../../types"; -import { getStripDiacriticsFn } from "../../../../util/fuse"; import { calcUnusedEntities, computeUsedEntities, @@ -88,7 +87,7 @@ export class HuiCardPicker extends LitElement { isCaseSensitive: false, minMatchCharLength: Math.min(filter.length, 2), threshold: 0.2, - getFn: getStripDiacriticsFn, + getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)), }; const fuse = new Fuse(cards, options); cards = fuse.search(stripDiacritics(filter)).map((result) => result.item); diff --git a/src/util/fuse.ts b/src/util/fuse.ts deleted file mode 100644 index 56157d7001..0000000000 --- a/src/util/fuse.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Fuse from "fuse.js"; -import { stripDiacritics } from "../common/string/strip-diacritics"; - -type GetFn = typeof Fuse.config.getFn; - -export const getStripDiacriticsFn: GetFn = (obj, path) => { - const value = Fuse.config.getFn(obj, path); - if (Array.isArray(value)) { - return value.map((v) => stripDiacritics(v ?? "")); - } - return stripDiacritics((value as string | undefined) ?? ""); -}; From ab38dad156791f843ad0aec9edf7b46bd9f78498 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 6 Aug 2024 16:55:24 +0200 Subject: [PATCH 3/4] Bumped version to 20240806.1 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d94cf13bac..75594e4866 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240806.0" +version = "20240806.1" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From d9ce20992cd70df27918d9462ec62ad51f4cffc2 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 2 Sep 2024 17:30:17 +0200 Subject: [PATCH 4/4] 20240902.0 (#21857) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependency @bundle-stats/plugin-webpack-filter to v4.15.0 (#21837) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency marked to v14.1.0 (#21829) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Bump actions/upload-artifact from 4.3.6 to 4.4.0 (#21850) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.6 to 4.4.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4.3.6...v4.4.0) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Add padding to no info badge (#21844) * Add padding to no info badge * Update src/panels/lovelace/badges/hui-entity-badge.ts Co-authored-by: Paul Bottein --------- Co-authored-by: Paul Bottein * Fix section not displayed when empty and string config (#21852) * Move edit mode actions next to section block (#21840) * Fix rendering of alerts in markdown when not breaking (#21856) * Perform action on every entity (#21845) * Bumped version to 20240902.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com> Co-authored-by: Joakim Sørensen --- .github/workflows/ci.yaml | 4 +- .github/workflows/nightly.yaml | 4 +- gallery/src/pages/misc/ha-markdown.markdown | 3 + gallery/src/pages/misc/ha-markdown.ts | 93 ++++++++++++ package.json | 4 +- pyproject.toml | 2 +- src/components/ha-markdown-element.ts | 20 ++- src/data/script_i18n.ts | 6 + .../lovelace/badges/hui-entity-badge.ts | 2 +- .../lovelace/sections/hui-grid-section.ts | 43 +----- .../lovelace/views/hui-sections-view.ts | 141 ++++++++++++------ src/translations/en.json | 1 + yarn.lock | 20 +-- 13 files changed, 241 insertions(+), 102 deletions(-) create mode 100644 gallery/src/pages/misc/ha-markdown.markdown create mode 100644 gallery/src/pages/misc/ha-markdown.ts diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7fb68b29a0..84d8995cc5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -89,7 +89,7 @@ jobs: env: IS_TEST: "true" - name: Upload bundle stats - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: frontend-bundle-stats path: build/stats/*.json @@ -113,7 +113,7 @@ jobs: env: IS_TEST: "true" - name: Upload bundle stats - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: supervisor-bundle-stats path: build/stats/*.json diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 530361e404..805f7c5e94 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -57,14 +57,14 @@ jobs: run: tar -czvf translations.tar.gz translations - name: Upload build artifacts - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: wheels path: dist/home_assistant_frontend*.whl if-no-files-found: error - name: Upload translations - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: translations path: translations.tar.gz diff --git a/gallery/src/pages/misc/ha-markdown.markdown b/gallery/src/pages/misc/ha-markdown.markdown new file mode 100644 index 0000000000..4e1bd1b608 --- /dev/null +++ b/gallery/src/pages/misc/ha-markdown.markdown @@ -0,0 +1,3 @@ +--- +title: Markdown +--- diff --git a/gallery/src/pages/misc/ha-markdown.ts b/gallery/src/pages/misc/ha-markdown.ts new file mode 100644 index 0000000000..600a9a4f02 --- /dev/null +++ b/gallery/src/pages/misc/ha-markdown.ts @@ -0,0 +1,93 @@ +import { css, html, LitElement } from "lit"; +import "../../../../src/components/ha-card"; +import "../../../../src/components/ha-markdown"; + +import { customElement } from "lit/decorators"; + +interface MarkdownContent { + content: string; + breaks: boolean; + allowSvg: boolean; + lazyImages: boolean; +} + +const mdContentwithDefaults = (md: Partial) => + ({ + breaks: false, + allowSvg: false, + lazyImages: false, + ...md, + }) as MarkdownContent; + +const generateContent = (md) => ` +\`\`\`json +${JSON.stringify({ ...md, content: undefined })} +\`\`\` + +--- + +${md.content} +`; + +const markdownContents: MarkdownContent[] = [ + mdContentwithDefaults({ + content: "_Hello_ **there** 👋, ~~nice~~ of you ||to|| show up.", + }), + ...[true, false].map((breaks) => + mdContentwithDefaults({ + breaks, + content: ` +![image](https://img.shields.io/badge/markdown-rendering-brightgreen) +![image](https://img.shields.io/badge/markdown-rendering-blue) + +> [!TIP] +> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer dictum quis ante eu eleifend. Integer sed [consectetur est, nec elementum magna](#). Fusce lobortis lectus ac rutrum tincidunt. Quisque suscipit gravida ante, in convallis risus vulputate non. + +key | description +-- | -- +lorem | ipsum + +- list item 1 +- list item 2 + + + `, + }) + ), +]; + +@customElement("demo-misc-ha-markdown") +export class DemoMiscMarkdown extends LitElement { + protected render() { + return html` +
+ ${markdownContents.map( + (md) => + html` + + ` + )} +
+ `; + } + + static get styles() { + return css` + ha-card { + margin: 12px; + padding: 12px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "demo-misc-ha-markdown": DemoMiscMarkdown; + } +} diff --git a/package.json b/package.json index 38c7ae5a33..259a19d815 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "leaflet-draw": "1.0.4", "lit": "2.8.0", "luxon": "3.5.0", - "marked": "14.0.0", + "marked": "14.1.0", "memoize-one": "6.0.0", "node-vibrant": "3.2.1-alpha.1", "proxy-polyfill": "0.3.2", @@ -155,7 +155,7 @@ "@babel/plugin-transform-runtime": "7.25.4", "@babel/preset-env": "7.25.4", "@babel/preset-typescript": "7.24.7", - "@bundle-stats/plugin-webpack-filter": "4.14.2", + "@bundle-stats/plugin-webpack-filter": "4.15.0", "@koa/cors": "5.0.0", "@lokalise/node-api": "12.7.0", "@octokit/auth-oauth-device": "7.1.1", diff --git a/pyproject.toml b/pyproject.toml index 7bcb25bd93..51e7b1af14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240829.0" +version = "20240902.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/components/ha-markdown-element.ts b/src/components/ha-markdown-element.ts index 5ca7fa66b2..e291a54cce 100644 --- a/src/components/ha-markdown-element.ts +++ b/src/components/ha-markdown-element.ts @@ -96,7 +96,25 @@ class HaMarkdownElement extends ReactiveElement { haAlertNode.append( ...Array.from(node.childNodes) - .map((child) => Array.from(child.childNodes)) + .map((child) => { + const arr = Array.from(child.childNodes); + if (!this.breaks && arr.length) { + // When we are not breaking, the first line of the blockquote is not considered, + // so we need to adjust the first child text content + const firstChild = arr[0]; + if ( + firstChild.nodeType === Node.TEXT_NODE && + firstChild.textContent === gitHubAlertMatch.input && + firstChild.textContent?.includes("\n") + ) { + firstChild.textContent = firstChild.textContent + .split("\n") + .slice(1) + .join("\n"); + } + } + return arr; + }) .reduce((acc, val) => acc.concat(val), []) .filter( (childNode) => diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index 150afc4220..64852bc6e7 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -127,6 +127,12 @@ const tryDescribeAction = ( targets.push( computeEntityRegistryName(hass, entityReg) || targetThing ); + } else if (targetThing === "all") { + targets.push( + hass.localize( + `${actionTranslationBaseKey}.service.description.target_every_entity` + ) + ); } else { targets.push( hass.localize( diff --git a/src/panels/lovelace/badges/hui-entity-badge.ts b/src/panels/lovelace/badges/hui-entity-badge.ts index af5b05e3e9..39aa9a193f 100644 --- a/src/panels/lovelace/badges/hui-entity-badge.ts +++ b/src/panels/lovelace/badges/hui-entity-badge.ts @@ -351,7 +351,7 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge { .badge.no-info { padding: 0; } - .badge:not(.no-icon) img { + .badge:not(.no-icon):not(.no-info) img { margin-left: -6px; margin-inline-start: -6px; margin-inline-end: initial; diff --git a/src/panels/lovelace/sections/hui-grid-section.ts b/src/panels/lovelace/sections/hui-grid-section.ts index 349521228b..8378b3e173 100644 --- a/src/panels/lovelace/sections/hui-grid-section.ts +++ b/src/panels/lovelace/sections/hui-grid-section.ts @@ -48,7 +48,10 @@ export class GridSection extends LitElement implements LovelaceSectionElement { private _cardConfigKeys = new WeakMap(); private _getKey(cardConfig: LovelaceCardConfig) { - if (!this._cardConfigKeys.has(cardConfig)) { + if ( + !this._cardConfigKeys.has(cardConfig) && + typeof cardConfig === "object" + ) { this._cardConfigKeys.set(cardConfig, Math.random().toString()); } return this._cardConfigKeys.get(cardConfig)!; @@ -62,20 +65,6 @@ export class GridSection extends LitElement implements LovelaceSectionElement { const editMode = Boolean(this.lovelace?.editMode && !this.isStrategy); return html` - ${this._config.title || this.lovelace?.editMode - ? html` -

- ${this._config.title || - this.hass.localize( - "ui.panel.lovelace.editor.section.unnamed_section" - )} -

- ` - : nothing} - ${editMode - ? html` -
-
- - - -
-
- ` - : nothing} - ${section} + ${ + sectionConfig?.title || this.lovelace?.editMode + ? html` +
+

+ ${sectionConfig?.title || + this.hass.localize( + "ui.panel.lovelace.editor.section.unnamed_section" + )} +

+ ${editMode + ? html` +
+ + + +
+ ` + : nothing} +
+ ` + : nothing + } + ${section} + `; } @@ -346,25 +367,6 @@ export class SectionsView extends LitElement implements LovelaceViewElement { } } - .section-actions { - position: absolute; - top: 0; - right: 0; - inset-inline-end: 0; - inset-inline-start: initial; - opacity: 1; - display: flex; - align-items: center; - justify-content: center; - transition: opacity 0.2s ease-in-out; - background-color: rgba(var(--rgb-card-background-color), 0.3); - border-radius: 18px; - background: var(--secondary-background-color); - --mdc-icon-button-size: 36px; - --mdc-icon-size: 20px; - color: var(--primary-text-color); - } - .handle { cursor: grab; padding: 8px; @@ -396,6 +398,55 @@ export class SectionsView extends LitElement implements LovelaceViewElement { margin: 16px 8px; text-align: center; } + + .section-header { + position: relative; + height: var(--row-height); + margin-bottom: var(--row-gap); + display: flex; + flex-direction: column; + justify-content: flex-end; + } + + .section-title { + color: var(--primary-text-color); + font-size: 20px; + font-weight: normal; + margin: 0px; + letter-spacing: 0.1px; + line-height: 32px; + text-align: var(--ha-view-sections-title-text-align, start); + min-height: 32px; + box-sizing: border-box; + padding: 0 10px 10px; + } + + .section-title.placeholder { + color: var(--secondary-text-color); + font-style: italic; + } + + .section-actions { + position: absolute; + height: 36px; + bottom: calc(-1 * var(--row-gap) - 2px); + right: 0; + inset-inline-end: 0; + inset-inline-start: initial; + opacity: 1; + display: flex; + align-items: center; + justify-content: center; + transition: opacity 0.2s ease-in-out; + background-color: rgba(var(--rgb-card-background-color), 0.3); + border-radius: var(--ha-card-border-radius, 12px); + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + background: var(--secondary-background-color); + --mdc-icon-button-size: 36px; + --mdc-icon-size: 20px; + color: var(--primary-text-color); + } `; } } diff --git a/src/translations/en.json b/src/translations/en.json index 97fd46952d..19e2c300ff 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3311,6 +3311,7 @@ "service_name_no_targets": "{domain} ''{name}''", "service": "Perform an action", "target_template": "templated {name}", + "target_every_entity": "every entity", "target_unknown_entity": "unknown entity", "target_unknown_device": "unknown device", "target_unknown_area": "unknown area", diff --git a/yarn.lock b/yarn.lock index a630b71858..0d2e5b0db9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1432,12 +1432,12 @@ __metadata: languageName: node linkType: hard -"@bundle-stats/plugin-webpack-filter@npm:4.14.2": - version: 4.14.2 - resolution: "@bundle-stats/plugin-webpack-filter@npm:4.14.2" +"@bundle-stats/plugin-webpack-filter@npm:4.15.0": + version: 4.15.0 + resolution: "@bundle-stats/plugin-webpack-filter@npm:4.15.0" peerDependencies: core-js: ^3.0.0 - checksum: 10/5024a0babd398e66f4a973f41ee521ab756bdb3d35ea994c2a6e4bf9e6fca28715a53e1431e1acd5837debc129ea9e784509d8afafb3ba082a397caaed570225 + checksum: 10/5b3bbc133ccc50a4f2e6e8c7e6e10dacc1c85cb176e934965777a8f1ca7b137707b704b77858d8c4fa9d665a92e0cfc99b1d07791d08c522e023fb3c39d8a705 languageName: node linkType: hard @@ -8920,7 +8920,7 @@ __metadata: "@babel/preset-typescript": "npm:7.24.7" "@babel/runtime": "npm:7.25.4" "@braintree/sanitize-url": "npm:7.1.0" - "@bundle-stats/plugin-webpack-filter": "npm:4.14.2" + "@bundle-stats/plugin-webpack-filter": "npm:4.15.0" "@codemirror/autocomplete": "npm:6.18.0" "@codemirror/commands": "npm:6.6.0" "@codemirror/language": "npm:6.10.2" @@ -9078,7 +9078,7 @@ __metadata: luxon: "npm:3.5.0" magic-string: "npm:0.30.11" map-stream: "npm:0.0.7" - marked: "npm:14.0.0" + marked: "npm:14.1.0" memoize-one: "npm:6.0.0" mocha: "npm:10.5.0" node-vibrant: "npm:3.2.1-alpha.1" @@ -10858,12 +10858,12 @@ __metadata: languageName: node linkType: hard -"marked@npm:14.0.0": - version: 14.0.0 - resolution: "marked@npm:14.0.0" +"marked@npm:14.1.0": + version: 14.1.0 + resolution: "marked@npm:14.1.0" bin: marked: bin/marked.js - checksum: 10/5f69e58e177bde75fb6145127c939c096d05494c5dff92d73af8a550097d6631c82e919f8a375e3743379a2623418151086b925a902a2be123590b887716f2bb + checksum: 10/1a930dd87a3994cc4fcc72c4668c548429d0e6363b8f7660193c106fa1cadcde5c813cfc3fe4be42b9f18b3652ba73469fb6c718215b0dbf8ddb9de2d1f5ab38 languageName: node linkType: hard