diff --git a/pyproject.toml b/pyproject.toml index 3c695ec8291b..55d7a058ef82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20231026.0" +version = "20231027.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/common/string/slugify.ts b/src/common/string/slugify.ts index ddf378059cbf..b7ddfed77c90 100644 --- a/src/common/string/slugify.ts +++ b/src/common/string/slugify.ts @@ -14,7 +14,7 @@ export const slugify = (value: string, delimiter = "_") => { .toString() .toLowerCase() .replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters - .replace(/(?<=\d),(?=\d)/g, "") // Remove Commas between numbers + .replace(/(\d),(?=\d)/g, "$1") // Remove Commas between numbers .replace(/[^a-z0-9]+/g, delimiter) // Replace all non-word characters .replace(new RegExp(`(${delimiter})\\1+`, "g"), "$1") // Replace multiple delimiters with single delimiter .replace(new RegExp(`^${delimiter}+`), "") // Trim delimiter from start of text diff --git a/src/components/ha-button.ts b/src/components/ha-button.ts index 473d08dd1589..b58f32c8b5c3 100644 --- a/src/components/ha-button.ts +++ b/src/components/ha-button.ts @@ -20,6 +20,10 @@ export class HaButton extends Button { .trailing-icon { display: flex; } + .slot-container { + width: 100%; + overflow: hidden; + } `, ]; } diff --git a/src/components/ha-date-range-picker.ts b/src/components/ha-date-range-picker.ts index 966d429d408c..ed5403872f07 100644 --- a/src/components/ha-date-range-picker.ts +++ b/src/components/ha-date-range-picker.ts @@ -46,6 +46,8 @@ export class HaDateRangePicker extends LitElement { @property() public ranges?: DateRangePickerRanges | false; + @state() private _ranges?: DateRangePickerRanges; + @property() public autoApply = false; @property() public timePicker = true; @@ -93,7 +95,7 @@ export class HaDateRangePicker extends LitElement { } ); - this.ranges = { + this._ranges = { [this.hass.localize("ui.components.date-range-picker.ranges.today")]: [ calcDate(today, startOfDay, this.hass.locale, this.hass.config, { weekStartsOn, @@ -206,15 +208,15 @@ export class HaDateRangePicker extends LitElement { .path=${mdiCalendar} >`} - ${this.ranges + ${this.ranges !== false && (this.ranges || this._ranges) ? html`
- ${Object.keys(this.ranges).map( - (name) => html` ${name} ` + ${Object.keys(this.ranges || this._ranges!).map( + (name) => html`${name}` )}
` @@ -234,7 +236,9 @@ export class HaDateRangePicker extends LitElement { } private _setDateRange(ev: CustomEvent) { - const dateRange = Object.values(this.ranges!)[ev.detail.index]; + const dateRange = Object.values(this.ranges || this._ranges!)[ + ev.detail.index + ]; const dateRangePicker = this._dateRangePicker; dateRangePicker.clickRange(dateRange); dateRangePicker.clickedApply(); diff --git a/src/components/ha-dialog.ts b/src/components/ha-dialog.ts index f061931322a4..feaceec93daf 100644 --- a/src/components/ha-dialog.ts +++ b/src/components/ha-dialog.ts @@ -94,6 +94,8 @@ export class HaDialog extends DialogBase { } .mdc-dialog__title { padding: 24px 24px 0 24px; + text-overflow: ellipsis; + overflow: hidden; } .mdc-dialog__actions { padding: 12px 24px 12px 24px; diff --git a/src/panels/config/entities/entity-registry-settings-editor.ts b/src/panels/config/entities/entity-registry-settings-editor.ts index 42c64edd64df..0241542addea 100644 --- a/src/panels/config/entities/entity-registry-settings-editor.ts +++ b/src/panels/config/entities/entity-registry-settings-editor.ts @@ -200,6 +200,8 @@ export class EntityRegistrySettingsEditor extends LitElement { this._name = this.entry.name || ""; this._icon = this.entry.icon || ""; + this._deviceClass = + this.entry.device_class || this.entry.original_device_class; this._origEntityId = this.entry.entity_id; this._areaId = this.entry.area_id; this._entityId = this.entry.entity_id; diff --git a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts index a1733e094040..5dc3abbcfe75 100644 --- a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts +++ b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts @@ -1,5 +1,12 @@ import { mdiPlus } from "@mdi/js"; -import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, +} from "lit"; import { customElement, property, state } from "lit/decorators"; import memoize from "memoize-one"; import { stringCompare } from "../../../../common/string/compare"; @@ -7,6 +14,7 @@ import { DataTableColumnContainer, RowClickedEvent, } from "../../../../components/data-table/ha-data-table"; +import "../../../../components/ha-card"; import "../../../../components/ha-fab"; import "../../../../components/ha-svg-icon"; import { @@ -21,7 +29,9 @@ import { showConfirmationDialog, } from "../../../../dialogs/generic/show-dialog-box"; import "../../../../layouts/hass-loading-screen"; +import "../../../../layouts/hass-subpage"; import "../../../../layouts/hass-tabs-subpage-data-table"; +import { haStyle } from "../../../../resources/styles"; import { HomeAssistant, Route } from "../../../../types"; import { loadLovelaceResources } from "../../../lovelace/common/load-resources"; import { lovelaceTabs } from "../ha-config-lovelace"; @@ -72,6 +82,36 @@ export class HaConfigLovelaceRescources extends LitElement { return html` `; } + if (this.hass.config.safe_mode) { + return html` + +
+ +
+

+ ${this.hass.localize( + "ui.panel.config.lovelace.resources.unavailable" + )} +

+

+ ${this.hass.localize( + "ui.panel.config.lovelace.resources.unavailable_safe_mode" + )} +

+
+
+
+
+ `; + } + return html` @@ -347,7 +347,8 @@ class HaPanelDevState extends LitElement { ev.preventDefault(); } - private _entityIdChanged() { + private _entityIdChanged(ev: CustomEvent) { + this._entityId = ev.detail.value; if (!this._entityId) { this._entity = undefined; this._state = ""; diff --git a/src/panels/energy/ha-panel-energy.ts b/src/panels/energy/ha-panel-energy.ts index 74ae7dfd7b6c..c9cf85f45bce 100644 --- a/src/panels/energy/ha-panel-energy.ts +++ b/src/panels/energy/ha-panel-energy.ts @@ -48,6 +48,9 @@ class PanelEnergy extends LitElement { if (oldHass?.locale !== this.hass.locale) { this._setLovelace(); } + if (oldHass && oldHass.localize !== this.hass.localize) { + this._reloadView(); + } } protected render(): TemplateResult { diff --git a/src/panels/lovelace/cards/hui-todo-list-card.ts b/src/panels/lovelace/cards/hui-todo-list-card.ts index f2d38bc64f83..68af5f2b5914 100644 --- a/src/panels/lovelace/cards/hui-todo-list-card.ts +++ b/src/panels/lovelace/cards/hui-todo-list-card.ts @@ -135,10 +135,14 @@ export class HuiTodoListCard public hassSubscribe(): Promise[] { return [ - this.hass!.connection.subscribeEvents( - () => this._fetchData(), - "shopping_list_updated" - ), + this.hass!.connection.subscribeEvents(() => { + if ( + this._entityId && + this.hass!.entities[this._entityId]?.platform === "shopping_list" + ) { + this._fetchData(); + } + }, "shopping_list_updated"), ]; } @@ -159,6 +163,15 @@ export class HuiTodoListCard ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } + + if ( + this._entityId && + oldHass && + oldHass.states[this._entityId] !== this.hass.states[this._entityId] && + this.hass.entities[this._entityId]?.platform !== "shopping_list" + ) { + this._fetchData(); + } } protected render() { diff --git a/src/panels/lovelace/common/load-resources.ts b/src/panels/lovelace/common/load-resources.ts index d8d0f5a1b3a9..3285d35d5272 100644 --- a/src/panels/lovelace/common/load-resources.ts +++ b/src/panels/lovelace/common/load-resources.ts @@ -10,11 +10,6 @@ export const loadLovelaceResources = ( resources: NonNullable, hass: HomeAssistant ) => { - // Don't load ressources on safe mode - // Sometimes, hass.config is null but it should not. - if (hass.config?.safe_mode) { - return; - } resources.forEach((resource) => { const normalizedUrl = new URL( resource.url, diff --git a/src/panels/lovelace/components/hui-energy-period-selector.ts b/src/panels/lovelace/components/hui-energy-period-selector.ts index aa78828abfe1..c06d3ab21063 100644 --- a/src/panels/lovelace/components/hui-energy-period-selector.ts +++ b/src/panels/lovelace/components/hui-energy-period-selector.ts @@ -65,7 +65,7 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) { @state() _endDate?: Date; - @state() private _ranges?: DateRangePickerRanges; + @state() private _ranges: DateRangePickerRanges = {}; @state() private _compare = false; diff --git a/src/panels/todo/ha-panel-todo.ts b/src/panels/todo/ha-panel-todo.ts index 8dbdd77e8c7c..abafcbf6035c 100644 --- a/src/panels/todo/ha-panel-todo.ts +++ b/src/panels/todo/ha-panel-todo.ts @@ -2,10 +2,10 @@ import { ResizeController } from "@lit-labs/observers/resize-controller"; import "@material/mwc-list"; import { mdiChevronDown, + mdiCommentProcessingOutline, mdiDelete, mdiDotsVertical, mdiInformationOutline, - mdiMicrophone, mdiPlus, } from "@mdi/js"; import { @@ -173,11 +173,13 @@ class PanelTodo extends LitElement { .x=${this.mobile ? 0 : undefined} > - ${this._entityId - ? this._entityId in this.hass.states - ? computeStateName(this.hass.states[this._entityId]) - : this._entityId - : ""} +
+ ${this._entityId + ? this._entityId in this.hass.states + ? computeStateName(this.hass.states[this._entityId]) + : this._entityId + : ""} +
` - : "Lists"} + : this.hass.localize("panel.todo")} ${listItems} @@ -216,8 +218,9 @@ class PanelTodo extends LitElement { : nothing}
  • - - ${this.hass.localize("ui.panel.todo.start_conversation")} + + + ${this.hass.localize("ui.panel.todo.assist")} ${entityRegistryEntry?.platform === "local_todo" ? html`
  • @@ -335,11 +338,18 @@ class PanelTodo extends LitElement { :host([mobile]) .lists { --mdc-menu-min-width: 100vw; } + :host(:not([mobile])) .lists ha-list-item { + max-width: calc(100vw - 120px); + } :host([mobile]) ha-button-menu { --mdc-shape-medium: 0 0 var(--mdc-shape-medium) var(--mdc-shape-medium); } + ha-button-menu { + max-width: 100%; + } ha-button-menu ha-button { + max-width: 100%; --mdc-theme-primary: currentColor; --mdc-typography-button-text-transform: none; --mdc-typography-button-font-size: var( @@ -360,6 +370,13 @@ class PanelTodo extends LitElement { ); --button-height: 40px; } + ha-button-menu ha-button div { + text-overflow: ellipsis; + width: 100%; + overflow: hidden; + white-space: nowrap; + display: block; + } `, ]; } diff --git a/src/state/connection-mixin.ts b/src/state/connection-mixin.ts index 08113c821a2c..c3cced5705c8 100644 --- a/src/state/connection-mixin.ts +++ b/src/state/connection-mixin.ts @@ -274,6 +274,10 @@ export const connectionMixin = >( // on reconnect always fetch config as we might miss an update while we were disconnected // @ts-ignore this.hass!.callWS({ type: "get_config" }).then((config: HassConfig) => { + if (config.safe_mode) { + // @ts-ignore Firefox supports forceGet + location.reload(true); + } this._updateHass({ config }); this.checkDataBaseMigration(); }); diff --git a/src/translations/en.json b/src/translations/en.json index c99285a8c0b9..e3047241c3d5 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2140,6 +2140,8 @@ "js": "JavaScript file (deprecated)", "module": "JavaScript module" }, + "unavailable": "Resources unavailable", + "unavailable_safe_mode": "Resources are not available in safe mode", "picker": { "headers": { "url": "URL", @@ -4520,7 +4522,6 @@ "never_triggered": "Never triggered" }, "todo-list": { - "lists": "To-do Lists", "checked_items": "Checked items", "clear_items": "Clear checked items", "add_item": "Add item", @@ -5094,7 +5095,7 @@ "description": "The Sensor card gives you a quick overview of your sensors state with an optional graph to visualize change over time." }, "todo-list": { - "name": "Todo list", + "name": "To-do list", "description": "The to-do list card allows you to add, edit, check-off, and clear items from your to-do list.", "integration_not_loaded": "This card requires the `todo` integration to be set up." }, @@ -5515,7 +5516,7 @@ } }, "todo": { - "start_conversation": "Start conversation", + "assist": "[%key:ui::panel::lovelace::menu::assist%]", "create_list": "Create list", "delete_list": "Delete list", "information": "Information",