diff --git a/hassio/src/addon-view/hassio-addon-info.ts b/hassio/src/addon-view/hassio-addon-info.ts index d8f5ff69db..f706c2ae66 100644 --- a/hassio/src/addon-view/hassio-addon-info.ts +++ b/hassio/src/addon-view/hassio-addon-info.ts @@ -452,7 +452,7 @@ class HassioAddonInfo extends LitElement { ` : ""} diff --git a/src/common/dom/dynamic-element-directive.ts b/src/common/dom/dynamic-element-directive.ts index 25ca9cfec8..a7b74ce1cd 100644 --- a/src/common/dom/dynamic-element-directive.ts +++ b/src/common/dom/dynamic-element-directive.ts @@ -4,7 +4,7 @@ export const dynamicElement = directive( (tag: string, properties?: { [key: string]: any }) => (part: Part): void => { if (!(part instanceof NodePart)) { throw new Error( - "dynamicContentDirective can only be used in content bindings" + "dynamicElementDirective can only be used in content bindings" ); } diff --git a/src/common/entity/domain_icon.ts b/src/common/entity/domain_icon.ts index 9d36310a2e..aff6fc346d 100644 --- a/src/common/entity/domain_icon.ts +++ b/src/common/entity/domain_icon.ts @@ -23,7 +23,7 @@ const fixedIcons = { homeassistant: "hass:home-assistant", homekit: "hass:home-automation", image_processing: "hass:image-filter-frames", - input_boolean: "hass:drawing", + input_boolean: "hass:toggle-switch-outline", input_datetime: "hass:calendar-clock", input_number: "hass:ray-vertex", input_select: "hass:format-list-bulleted", diff --git a/src/components/ha-icon-input.ts b/src/components/ha-icon-input.ts new file mode 100644 index 0000000000..9621e267ed --- /dev/null +++ b/src/components/ha-icon-input.ts @@ -0,0 +1,65 @@ +import { + html, + css, + LitElement, + TemplateResult, + property, + customElement, +} from "lit-element"; + +import "@polymer/paper-input/paper-input"; +import "./ha-icon"; +import { fireEvent } from "../common/dom/fire_event"; + +@customElement("ha-icon-input") +export class HaIconInput extends LitElement { + @property() public value?: string; + @property() public label?: string; + @property() public placeholder?: string; + @property({ attribute: "error-message" }) public errorMessage?: string; + @property({ type: Boolean }) public disabled = false; + + protected render(): TemplateResult { + return html` + + ${this.value || this.placeholder + ? html` + + + ` + : ""} + + `; + } + + private _valueChanged(ev: CustomEvent) { + this.value = ev.detail.value; + fireEvent( + this, + "value-changed", + { value: ev.detail.value }, + { + bubbles: false, + composed: false, + } + ); + } + + static get styles() { + return css` + ha-icon { + position: relative; + bottom: 4px; + } + `; + } +} diff --git a/src/components/ha-related-items.ts b/src/components/ha-related-items.ts index d1b900578b..bc810e48e0 100644 --- a/src/components/ha-related-items.ts +++ b/src/components/ha-related-items.ts @@ -70,9 +70,7 @@ export class HaRelatedItems extends SubscribeMixin(LitElement) { } if (Object.keys(this._related).length === 0) { return html` -

- ${this.hass.localize("ui.components.related-items.no_related_found")} -

+ ${this.hass.localize("ui.components.related-items.no_related_found")} `; } return html` diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts index 58fad95cf1..c4b94aab21 100644 --- a/src/data/entity_registry.ts +++ b/src/data/entity_registry.ts @@ -6,14 +6,23 @@ import { debounce } from "../common/util/debounce"; export interface EntityRegistryEntry { entity_id: string; name: string; + icon?: string; platform: string; config_entry_id?: string; device_id?: string; disabled_by: string | null; } +export interface ExtEntityRegistryEntry extends EntityRegistryEntry { + unique_id: string; + capabilities: object; + original_name?: string; + original_icon?: string; +} + export interface EntityRegistryEntryUpdateParams { name?: string | null; + icon?: string | null; disabled_by?: string | null; new_entity_id?: string; } @@ -29,12 +38,21 @@ export const computeEntityRegistryName = ( return state ? computeStateName(state) : null; }; +export const getExtendedEntityRegistryEntry = ( + hass: HomeAssistant, + entityId: string +): Promise => + hass.callWS({ + type: "config/entity_registry/get", + entity_id: entityId, + }); + export const updateEntityRegistryEntry = ( hass: HomeAssistant, entityId: string, updates: Partial -): Promise => - hass.callWS({ +): Promise => + hass.callWS({ type: "config/entity_registry/update", entity_id: entityId, ...updates, diff --git a/src/data/frontend.ts b/src/data/frontend.ts index 83a2db1ac7..8760859c65 100644 --- a/src/data/frontend.ts +++ b/src/data/frontend.ts @@ -59,3 +59,12 @@ export const getOptimisticFrontendUserDataCollection = < `_frontendUserData-${userDataKey}`, () => fetchFrontendUserData(conn, userDataKey) ); + +export const subscribeFrontendUserData = ( + conn: Connection, + userDataKey: UserDataKey, + onChange: (state: FrontendUserData[UserDataKey] | null) => void +) => + getOptimisticFrontendUserDataCollection(conn, userDataKey).subscribe( + onChange + ); diff --git a/src/data/input-select.ts b/src/data/input-select.ts deleted file mode 100644 index c119cd0290..0000000000 --- a/src/data/input-select.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { HomeAssistant } from "../types"; - -export const setInputSelectOption = ( - hass: HomeAssistant, - entity: string, - option: string -) => - hass.callService("input_select", "select_option", { - option, - entity_id: entity, - }); diff --git a/src/data/input_boolean.ts b/src/data/input_boolean.ts new file mode 100644 index 0000000000..b0393bbd92 --- /dev/null +++ b/src/data/input_boolean.ts @@ -0,0 +1,43 @@ +import { HomeAssistant } from "../types"; + +export interface InputBoolean { + id: string; + name: string; + icon?: string; + initial?: boolean; +} + +export interface InputBooleanMutableParams { + name: string; + icon: string; + initial: boolean; +} + +export const fetchInputBoolean = (hass: HomeAssistant) => + hass.callWS({ type: "input_boolean/list" }); + +export const createInputBoolean = ( + hass: HomeAssistant, + values: InputBooleanMutableParams +) => + hass.callWS({ + type: "input_boolean/create", + ...values, + }); + +export const updateInputBoolean = ( + hass: HomeAssistant, + id: string, + updates: Partial +) => + hass.callWS({ + type: "input_boolean/update", + input_boolean_id: id, + ...updates, + }); + +export const deleteInputBoolean = (hass: HomeAssistant, id: string) => + hass.callWS({ + type: "input_boolean/delete", + input_boolean_id: id, + }); diff --git a/src/data/input_datetime.ts b/src/data/input_datetime.ts index 600035783f..16a2f1b09d 100644 --- a/src/data/input_datetime.ts +++ b/src/data/input_datetime.ts @@ -1,5 +1,22 @@ import { HomeAssistant } from "../types"; +export interface InputDateTime { + id: string; + name: string; + icon?: string; + initial?: string; + has_time: boolean; + has_date: boolean; +} + +export interface InputDateTimeMutableParams { + name: string; + icon: string; + initial: string; + has_time: boolean; + has_date: boolean; +} + export const setInputDateTimeValue = ( hass: HomeAssistant, entityId: string, @@ -9,3 +26,32 @@ export const setInputDateTimeValue = ( const param = { entity_id: entityId, time, date }; hass.callService(entityId.split(".", 1)[0], "set_datetime", param); }; + +export const fetchInputDateTime = (hass: HomeAssistant) => + hass.callWS({ type: "input_datetime/list" }); + +export const createInputDateTime = ( + hass: HomeAssistant, + values: InputDateTimeMutableParams +) => + hass.callWS({ + type: "input_datetime/create", + ...values, + }); + +export const updateInputDateTime = ( + hass: HomeAssistant, + id: string, + updates: Partial +) => + hass.callWS({ + type: "input_datetime/update", + input_datetime_id: id, + ...updates, + }); + +export const deleteInputDateTime = (hass: HomeAssistant, id: string) => + hass.callWS({ + type: "input_datetime/delete", + input_datetime_id: id, + }); diff --git a/src/data/input_number.ts b/src/data/input_number.ts new file mode 100644 index 0000000000..2a1d9c46ad --- /dev/null +++ b/src/data/input_number.ts @@ -0,0 +1,53 @@ +import { HomeAssistant } from "../types"; + +export interface InputNumber { + id: string; + name: string; + min: number; + max: number; + icon?: string; + initial?: number; + step?: number; + mode?: "box" | "slider"; + unit_of_measurement?: string; +} + +export interface InputNumberMutableParams { + name: string; + icon: string; + initial: number; + min: number; + max: number; + step: number; + mode: "box" | "slider"; + unit_of_measurement?: string; +} + +export const fetchInputNumber = (hass: HomeAssistant) => + hass.callWS({ type: "input_number/list" }); + +export const createInputNumber = ( + hass: HomeAssistant, + values: InputNumberMutableParams +) => + hass.callWS({ + type: "input_number/create", + ...values, + }); + +export const updateInputNumber = ( + hass: HomeAssistant, + id: string, + updates: Partial +) => + hass.callWS({ + type: "input_number/update", + input_number_id: id, + ...updates, + }); + +export const deleteInputNumber = (hass: HomeAssistant, id: string) => + hass.callWS({ + type: "input_number/delete", + input_number_id: id, + }); diff --git a/src/data/input_select.ts b/src/data/input_select.ts new file mode 100644 index 0000000000..3c68d5f66b --- /dev/null +++ b/src/data/input_select.ts @@ -0,0 +1,55 @@ +import { HomeAssistant } from "../types"; + +export interface InputSelect { + id: string; + name: string; + options: string[]; + icon?: string; + initial?: string; +} + +export interface InputSelectMutableParams { + name: string; + icon: string; + initial: string; + options: string[]; +} + +export const setInputSelectOption = ( + hass: HomeAssistant, + entity: string, + option: string +) => + hass.callService("input_select", "select_option", { + option, + entity_id: entity, + }); + +export const fetchInputSelect = (hass: HomeAssistant) => + hass.callWS({ type: "input_select/list" }); + +export const createInputSelect = ( + hass: HomeAssistant, + values: InputSelectMutableParams +) => + hass.callWS({ + type: "input_select/create", + ...values, + }); + +export const updateInputSelect = ( + hass: HomeAssistant, + id: string, + updates: Partial +) => + hass.callWS({ + type: "input_select/update", + input_select_id: id, + ...updates, + }); + +export const deleteInputSelect = (hass: HomeAssistant, id: string) => + hass.callWS({ + type: "input_select/delete", + input_select_id: id, + }); diff --git a/src/data/input_text.ts b/src/data/input_text.ts index 04ee6c334c..5e6c7e1225 100644 --- a/src/data/input_text.ts +++ b/src/data/input_text.ts @@ -1,7 +1,57 @@ import { HomeAssistant } from "../types"; +export interface InputText { + id: string; + name: string; + icon?: string; + initial?: string; + min?: number; + max?: number; + pattern?: string; + mode?: "text" | "password"; +} + +export interface InputTextMutableParams { + name: string; + icon: string; + initial: string; + min: number; + max: number; + pattern: string; + mode: "text" | "password"; +} + export const setValue = (hass: HomeAssistant, entity: string, value: string) => hass.callService(entity.split(".", 1)[0], "set_value", { value, entity_id: entity, }); + +export const fetchInputText = (hass: HomeAssistant) => + hass.callWS({ type: "input_text/list" }); + +export const createInputText = ( + hass: HomeAssistant, + values: InputTextMutableParams +) => + hass.callWS({ + type: "input_text/create", + ...values, + }); + +export const updateInputText = ( + hass: HomeAssistant, + id: string, + updates: Partial +) => + hass.callWS({ + type: "input_text/update", + input_text_id: id, + ...updates, + }); + +export const deleteInputText = (hass: HomeAssistant, id: string) => + hass.callWS({ + type: "input_text/delete", + input_text_id: id, + }); diff --git a/src/dialogs/generic/dialog-box.ts b/src/dialogs/generic/dialog-box.ts index 77b37f2092..ff19b3d4bb 100644 --- a/src/dialogs/generic/dialog-box.ts +++ b/src/dialogs/generic/dialog-box.ts @@ -129,6 +129,10 @@ class DialogBox extends LitElement { return [ haStyleDialog, css` + :host([inert]) { + pointer-events: initial !important; + cursor: initial !important; + } ha-paper-dialog { min-width: 400px; max-width: 500px; diff --git a/src/dialogs/ha-more-info-dialog.js b/src/dialogs/ha-more-info-dialog.js index 878f17473d..135855db5b 100644 --- a/src/dialogs/ha-more-info-dialog.js +++ b/src/dialogs/ha-more-info-dialog.js @@ -8,7 +8,6 @@ import "../resources/ha-style"; import "./more-info/more-info-controls"; import { computeStateDomain } from "../common/entity/compute_state_domain"; -import { isComponentLoaded } from "../common/config/is_component_loaded"; import DialogMixin from "../mixins/dialog-mixin"; @@ -81,7 +80,6 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) { hass="[[hass]]" state-obj="[[stateObj]]" dialog-element="[[_dialogElement()]]" - registry-entry="[[_registryInfo]]" large="{{large}}" > `; @@ -102,8 +100,6 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) { observer: "_largeChanged", }, - _registryInfo: Object, - dataDomain: { computed: "_computeDomain(stateObj)", reflectToAttribute: true, @@ -127,11 +123,10 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) { return hass.states[hass.moreInfoEntityId] || null; } - async _stateObjChanged(newVal, oldVal) { + async _stateObjChanged(newVal) { if (!newVal) { this.setProperties({ opened: false, - _registryInfo: null, large: false, }); return; @@ -144,25 +139,6 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) { this.opened = true; }) ); - - if ( - !isComponentLoaded(this.hass, "config") || - (oldVal && oldVal.entity_id === newVal.entity_id) - ) { - return; - } - - if (this.hass.user.is_admin) { - try { - const info = await this.hass.callWS({ - type: "config/entity_registry/get", - entity_id: newVal.entity_id, - }); - this._registryInfo = info; - } catch (err) { - this._registryInfo = null; - } - } } _dialogOpenChanged(newVal) { diff --git a/src/dialogs/more-info/controls/more-info-person.ts b/src/dialogs/more-info/controls/more-info-person.ts index 4e5ae33c32..d4c2bb2e0c 100644 --- a/src/dialogs/more-info/controls/more-info-person.ts +++ b/src/dialogs/more-info/controls/more-info-person.ts @@ -39,7 +39,8 @@ class MoreInfoPerson extends LitElement { > ` : ""} - ${this.hass.user?.is_admin && + ${!__DEMO__ && + this.hass.user?.is_admin && this.stateObj.state === "not_home" && this.stateObj.attributes.latitude && this.stateObj.attributes.longitude diff --git a/src/dialogs/more-info/more-info-controls.js b/src/dialogs/more-info/more-info-controls.js index c4ff5e4f6f..0da3f5ac7c 100644 --- a/src/dialogs/more-info/more-info-controls.js +++ b/src/dialogs/more-info/more-info-controls.js @@ -22,7 +22,7 @@ import LocalizeMixin from "../../mixins/localize-mixin"; import { computeRTL } from "../../common/util/compute_rtl"; import { removeEntityRegistryEntry } from "../../data/entity_registry"; import { showConfirmationDialog } from "../generic/show-dialog-box"; -import { showEntityRegistryDetailDialog } from "../../panels/config/entities/show-dialog-entity-registry-detail"; +import { showEntityEditorDialog } from "../../panels/config/entities/show-dialog-entity-editor"; const DOMAINS_NO_INFO = ["camera", "configurator", "history_graph"]; const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"]; @@ -88,7 +88,7 @@ class MoreInfoControls extends LocalizeMixin(EventsMixin(PolymerElement)) {
[[_computeStateName(stateObj)]]
-