mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-27 14:57:20 +00:00
Add state and related to entity reg dialog (#4473)
* Add state and related to entity reg dialog * Replace more-info-settings, remove state tab add state button
This commit is contained in:
parent
a544295167
commit
ae8a9940ed
323
src/components/ha-related-items.ts
Normal file
323
src/components/ha-related-items.ts
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
CSSResult,
|
||||||
|
css,
|
||||||
|
} from "lit-element";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import {
|
||||||
|
AreaRegistryEntry,
|
||||||
|
subscribeAreaRegistry,
|
||||||
|
} from "../data/area_registry";
|
||||||
|
import { ConfigEntry, getConfigEntries } from "../data/config_entries";
|
||||||
|
import {
|
||||||
|
DeviceRegistryEntry,
|
||||||
|
subscribeDeviceRegistry,
|
||||||
|
} from "../data/device_registry";
|
||||||
|
import { SceneEntity } from "../data/scene";
|
||||||
|
import { findRelated, ItemType, RelatedResult } from "../data/search";
|
||||||
|
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
import "./ha-switch";
|
||||||
|
|
||||||
|
@customElement("ha-related-items")
|
||||||
|
export class HaRelatedItems extends SubscribeMixin(LitElement) {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
@property() public itemType!: ItemType;
|
||||||
|
@property() public itemId!: string;
|
||||||
|
@property() private _entries?: ConfigEntry[];
|
||||||
|
@property() private _devices?: DeviceRegistryEntry[];
|
||||||
|
@property() private _areas?: AreaRegistryEntry[];
|
||||||
|
@property() private _related?: RelatedResult;
|
||||||
|
|
||||||
|
public hassSubscribe(): UnsubscribeFunc[] {
|
||||||
|
return [
|
||||||
|
subscribeDeviceRegistry(this.hass.connection!, (devices) => {
|
||||||
|
this._devices = devices;
|
||||||
|
}),
|
||||||
|
subscribeAreaRegistry(this.hass.connection!, (areas) => {
|
||||||
|
this._areas = areas;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
getConfigEntries(this.hass).then((configEntries) => {
|
||||||
|
this._entries = configEntries;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (
|
||||||
|
(changedProps.has("itemId") || changedProps.has("itemType")) &&
|
||||||
|
this.itemId &&
|
||||||
|
this.itemType
|
||||||
|
) {
|
||||||
|
this._findRelated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
if (!this._related) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
${this._related.config_entry && this._entries
|
||||||
|
? this._related.config_entry.map((relatedConfigEntryId) => {
|
||||||
|
const entry: ConfigEntry | undefined = this._entries!.find(
|
||||||
|
(configEntry) => configEntry.entry_id === relatedConfigEntryId
|
||||||
|
);
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.components.related-items.integration"
|
||||||
|
)}:
|
||||||
|
</h3>
|
||||||
|
<a
|
||||||
|
href="/config/integrations/config_entry/${relatedConfigEntryId}"
|
||||||
|
@click=${this._close}
|
||||||
|
>
|
||||||
|
${this.hass.localize(`component.${entry.domain}.config.title`)}:
|
||||||
|
${entry.title}
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
: ""}
|
||||||
|
${this._related.device && this._devices
|
||||||
|
? this._related.device.map((relatedDeviceId) => {
|
||||||
|
const device: DeviceRegistryEntry | undefined = this._devices!.find(
|
||||||
|
(dev) => dev.id === relatedDeviceId
|
||||||
|
);
|
||||||
|
if (!device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize("ui.components.related-items.device")}:
|
||||||
|
</h3>
|
||||||
|
<a
|
||||||
|
href="/config/devices/device/${relatedDeviceId}"
|
||||||
|
@click=${this._close}
|
||||||
|
>
|
||||||
|
${device.name_by_user || device.name}
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
: ""}
|
||||||
|
${this._related.area && this._areas
|
||||||
|
? this._related.area.map((relatedAreaId) => {
|
||||||
|
const area: AreaRegistryEntry | undefined = this._areas!.find(
|
||||||
|
(ar) => ar.area_id === relatedAreaId
|
||||||
|
);
|
||||||
|
if (!area) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize("ui.components.related-items.area")}:
|
||||||
|
</h3>
|
||||||
|
${area.name}
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
: ""}
|
||||||
|
${this._related.entity
|
||||||
|
? html`
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize("ui.components.related-items.entity")}:
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
${this._related.entity.map((entityId) => {
|
||||||
|
const entity: HassEntity | undefined = this.hass.states[
|
||||||
|
entityId
|
||||||
|
];
|
||||||
|
if (!entity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
@click=${this._openMoreInfo}
|
||||||
|
.entityId="${entityId}"
|
||||||
|
class="link"
|
||||||
|
>
|
||||||
|
${entity.attributes.friendly_name || entityId}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._related.group
|
||||||
|
? html`
|
||||||
|
<h3>${this.hass.localize("ui.components.related-items.group")}:</h3>
|
||||||
|
<ul>
|
||||||
|
${this._related.group.map((groupId) => {
|
||||||
|
const group: HassEntity | undefined = this.hass.states[groupId];
|
||||||
|
if (!group) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="link"
|
||||||
|
@click=${this._openMoreInfo}
|
||||||
|
.entityId="${groupId}"
|
||||||
|
>
|
||||||
|
${group.attributes.friendly_name || group.entity_id}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._related.scene
|
||||||
|
? html`
|
||||||
|
<h3>${this.hass.localize("ui.components.related-items.scene")}:</h3>
|
||||||
|
<ul>
|
||||||
|
${this._related.scene.map((sceneId) => {
|
||||||
|
const scene: SceneEntity | undefined = this.hass.states[
|
||||||
|
sceneId
|
||||||
|
];
|
||||||
|
if (!scene) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="link"
|
||||||
|
@click=${this._openMoreInfo}
|
||||||
|
.entityId="${sceneId}"
|
||||||
|
>
|
||||||
|
${scene.attributes.friendly_name || scene.entity_id}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._related.automation
|
||||||
|
? html`
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize("ui.components.related-items.automation")}:
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
${this._related.automation.map((automationId) => {
|
||||||
|
const automation: HassEntity | undefined = this.hass.states[
|
||||||
|
automationId
|
||||||
|
];
|
||||||
|
if (!automation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="link"
|
||||||
|
@click=${this._openMoreInfo}
|
||||||
|
.entityId="${automationId}"
|
||||||
|
>
|
||||||
|
${automation.attributes.friendly_name ||
|
||||||
|
automation.entity_id}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._related.script
|
||||||
|
? html`
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize("ui.components.related-items.script")}:
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
${this._related.script.map((scriptId) => {
|
||||||
|
const script: HassEntity | undefined = this.hass.states[
|
||||||
|
scriptId
|
||||||
|
];
|
||||||
|
if (!script) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="link"
|
||||||
|
@click=${this._openMoreInfo}
|
||||||
|
.entityId="${scriptId}"
|
||||||
|
>
|
||||||
|
${script.attributes.friendly_name || script.entity_id}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _findRelated() {
|
||||||
|
this._related = await findRelated(this.hass, this.itemType, this.itemId);
|
||||||
|
await this.updateComplete;
|
||||||
|
fireEvent(this, "iron-resize");
|
||||||
|
}
|
||||||
|
|
||||||
|
private _openMoreInfo(ev: CustomEvent) {
|
||||||
|
const entityId = (ev.target as any).entityId;
|
||||||
|
fireEvent(this, "hass-more-info", { entityId });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _close() {
|
||||||
|
fireEvent(this, "close-dialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
a {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
button.link {
|
||||||
|
color: var(--primary-color);
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border-width: initial;
|
||||||
|
border-style: none;
|
||||||
|
border-color: initial;
|
||||||
|
border-image: initial;
|
||||||
|
padding: 0px;
|
||||||
|
font: inherit;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-family: var(--paper-font-title_-_font-family);
|
||||||
|
-webkit-font-smoothing: var(
|
||||||
|
--paper-font-title_-_-webkit-font-smoothing
|
||||||
|
);
|
||||||
|
font-size: var(--paper-font-title_-_font-size);
|
||||||
|
font-weight: var(--paper-font-headline-_font-weight);
|
||||||
|
letter-spacing: var(--paper-font-title_-_letter-spacing);
|
||||||
|
line-height: var(--paper-font-title_-_line-height);
|
||||||
|
opacity: var(--dark-primary-opacity);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-related-items": HaRelatedItems;
|
||||||
|
}
|
||||||
|
}
|
33
src/data/search.ts
Normal file
33
src/data/search.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export interface RelatedResult {
|
||||||
|
area?: string[];
|
||||||
|
automation?: string[];
|
||||||
|
config_entry?: string[];
|
||||||
|
device?: string[];
|
||||||
|
entity?: string[];
|
||||||
|
group?: string[];
|
||||||
|
scene?: string[];
|
||||||
|
script?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ItemType =
|
||||||
|
| "area"
|
||||||
|
| "automation"
|
||||||
|
| "config_entry"
|
||||||
|
| "device"
|
||||||
|
| "entity"
|
||||||
|
| "group"
|
||||||
|
| "scene"
|
||||||
|
| "script";
|
||||||
|
|
||||||
|
export const findRelated = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
itemType: ItemType,
|
||||||
|
itemId: string
|
||||||
|
): Promise<RelatedResult> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "search/related",
|
||||||
|
item_type: itemType,
|
||||||
|
item_id: itemId,
|
||||||
|
});
|
@ -6,7 +6,6 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|||||||
import "../resources/ha-style";
|
import "../resources/ha-style";
|
||||||
|
|
||||||
import "./more-info/more-info-controls";
|
import "./more-info/more-info-controls";
|
||||||
import "./more-info/more-info-settings";
|
|
||||||
|
|
||||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||||
@ -26,8 +25,7 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) {
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
more-info-controls,
|
more-info-controls {
|
||||||
more-info-settings {
|
|
||||||
--more-info-header-background: var(--secondary-background-color);
|
--more-info-header-background: var(--secondary-background-color);
|
||||||
--more-info-header-color: var(--primary-text-color);
|
--more-info-header-color: var(--primary-text-color);
|
||||||
--ha-more-info-app-toolbar-title: {
|
--ha-more-info-app-toolbar-title: {
|
||||||
@ -46,8 +44,7 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) {
|
|||||||
|
|
||||||
/* overrule the ha-style-dialog max-height on small screens */
|
/* overrule the ha-style-dialog max-height on small screens */
|
||||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
more-info-controls,
|
more-info-controls {
|
||||||
more-info-settings {
|
|
||||||
--more-info-header-background: var(--primary-color);
|
--more-info-header-background: var(--primary-color);
|
||||||
--more-info-header-color: var(--text-primary-color);
|
--more-info-header-color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
@ -79,24 +76,14 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template is="dom-if" if="[[!_page]]">
|
|
||||||
<more-info-controls
|
<more-info-controls
|
||||||
class="no-padding"
|
class="no-padding"
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
state-obj="[[stateObj]]"
|
state-obj="[[stateObj]]"
|
||||||
dialog-element="[[_dialogElement]]"
|
dialog-element="[[_dialogElement]]"
|
||||||
can-configure="[[_registryInfo]]"
|
registry-entry="[[_registryInfo]]"
|
||||||
large="{{large}}"
|
large="{{large}}"
|
||||||
></more-info-controls>
|
></more-info-controls>
|
||||||
</template>
|
|
||||||
<template is="dom-if" if='[[_equals(_page, "settings")]]'>
|
|
||||||
<more-info-settings
|
|
||||||
class="no-padding"
|
|
||||||
hass="[[hass]]"
|
|
||||||
state-obj="[[stateObj]]"
|
|
||||||
registry-info="{{_registryInfo}}"
|
|
||||||
></more-info-settings>
|
|
||||||
</template>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,11 +105,6 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) {
|
|||||||
_dialogElement: Object,
|
_dialogElement: Object,
|
||||||
_registryInfo: Object,
|
_registryInfo: Object,
|
||||||
|
|
||||||
_page: {
|
|
||||||
type: String,
|
|
||||||
value: null,
|
|
||||||
},
|
|
||||||
|
|
||||||
dataDomain: {
|
dataDomain: {
|
||||||
computed: "_computeDomain(stateObj)",
|
computed: "_computeDomain(stateObj)",
|
||||||
reflectToAttribute: true,
|
reflectToAttribute: true,
|
||||||
@ -137,9 +119,6 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) {
|
|||||||
ready() {
|
ready() {
|
||||||
super.ready();
|
super.ready();
|
||||||
this._dialogElement = this;
|
this._dialogElement = this;
|
||||||
this.addEventListener("more-info-page", (ev) => {
|
|
||||||
this._page = ev.detail.page;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_computeDomain(stateObj) {
|
_computeDomain(stateObj) {
|
||||||
@ -154,7 +133,6 @@ class HaMoreInfoDialog extends DialogMixin(PolymerElement) {
|
|||||||
if (!newVal) {
|
if (!newVal) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
opened: false,
|
opened: false,
|
||||||
_page: null,
|
|
||||||
_registryInfo: null,
|
_registryInfo: null,
|
||||||
large: false,
|
large: false,
|
||||||
});
|
});
|
||||||
|
@ -5,6 +5,7 @@ declare global {
|
|||||||
// for fire event
|
// for fire event
|
||||||
interface HASSDomEvents {
|
interface HASSDomEvents {
|
||||||
"show-dialog": ShowDialogParams<unknown>;
|
"show-dialog": ShowDialogParams<unknown>;
|
||||||
|
"close-dialog": undefined;
|
||||||
}
|
}
|
||||||
// for add event listener
|
// for add event listener
|
||||||
interface HTMLElementEventMap {
|
interface HTMLElementEventMap {
|
||||||
|
@ -22,6 +22,7 @@ import LocalizeMixin from "../../mixins/localize-mixin";
|
|||||||
import { computeRTL } from "../../common/util/compute_rtl";
|
import { computeRTL } from "../../common/util/compute_rtl";
|
||||||
import { removeEntityRegistryEntry } from "../../data/entity_registry";
|
import { removeEntityRegistryEntry } from "../../data/entity_registry";
|
||||||
import { showConfirmationDialog } from "../confirmation/show-dialog-confirmation";
|
import { showConfirmationDialog } from "../confirmation/show-dialog-confirmation";
|
||||||
|
import { showEntityRegistryDetailDialog } from "../../panels/config/entities/show-dialog-entity-registry-detail";
|
||||||
|
|
||||||
const DOMAINS_NO_INFO = ["camera", "configurator", "history_graph"];
|
const DOMAINS_NO_INFO = ["camera", "configurator", "history_graph"];
|
||||||
const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"];
|
const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"];
|
||||||
@ -87,7 +88,7 @@ class MoreInfoControls extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
<div class="main-title" main-title="" on-click="enlarge">
|
<div class="main-title" main-title="" on-click="enlarge">
|
||||||
[[_computeStateName(stateObj)]]
|
[[_computeStateName(stateObj)]]
|
||||||
</div>
|
</div>
|
||||||
<template is="dom-if" if="[[canConfigure]]">
|
<template is="dom-if" if="[[registryEntry]]">
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
aria-label$="[[localize('ui.dialogs.more_info_control.settings')]]"
|
aria-label$="[[localize('ui.dialogs.more_info_control.settings')]]"
|
||||||
icon="hass:settings"
|
icon="hass:settings"
|
||||||
@ -158,7 +159,7 @@ class MoreInfoControls extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
dialogElement: Object,
|
dialogElement: Object,
|
||||||
canConfigure: Boolean,
|
registryEntry: Object,
|
||||||
|
|
||||||
domain: {
|
domain: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -259,7 +260,8 @@ class MoreInfoControls extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_gotoSettings() {
|
_gotoSettings() {
|
||||||
this.fire("more-info-page", { page: "settings" });
|
showEntityRegistryDetailDialog(this, { entry: this.registryEntry });
|
||||||
|
this.fire("hass-more-info", { entityId: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
_gotoEdit() {
|
_gotoEdit() {
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
|
||||||
import "@polymer/paper-input/paper-input";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
|
|
||||||
import { EventsMixin } from "../../mixins/events-mixin";
|
|
||||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
|
||||||
|
|
||||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
|
||||||
import { updateEntityRegistryEntry } from "../../data/entity_registry";
|
|
||||||
import { showSaveSuccessToast } from "../../util/toast-saved-success";
|
|
||||||
|
|
||||||
import "../../components/ha-paper-icon-button-arrow-prev";
|
|
||||||
/*
|
|
||||||
* @appliesMixin EventsMixin
|
|
||||||
* @appliesMixin LocalizeMixin
|
|
||||||
*/
|
|
||||||
class MoreInfoSettings extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
app-toolbar {
|
|
||||||
color: var(--more-info-header-color);
|
|
||||||
background-color: var(--more-info-header-background);
|
|
||||||
|
|
||||||
/* to fit save button */
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
app-toolbar [main-title] {
|
|
||||||
@apply --ha-more-info-app-toolbar-title;
|
|
||||||
}
|
|
||||||
|
|
||||||
app-toolbar mwc-button {
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin: 0;
|
|
||||||
--mdc-theme-primary: var(--more-info-header-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form {
|
|
||||||
padding: 0 24px 24px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<app-toolbar>
|
|
||||||
<ha-paper-icon-button-arrow-prev
|
|
||||||
aria-label$="[[localize('ui.dialogs.more_info_settings.back')]]"
|
|
||||||
on-click="_backTapped"
|
|
||||||
></ha-paper-icon-button-arrow-prev>
|
|
||||||
<div main-title="">[[_computeStateName(stateObj)]]</div>
|
|
||||||
<mwc-button on-click="_save" disabled="[[_computeInvalid(_entityId)]]"
|
|
||||||
>[[localize('ui.dialogs.more_info_settings.save')]]</mwc-button
|
|
||||||
>
|
|
||||||
</app-toolbar>
|
|
||||||
|
|
||||||
<div class="form">
|
|
||||||
<paper-input
|
|
||||||
value="{{_name}}"
|
|
||||||
label="[[localize('ui.dialogs.more_info_settings.name')]]"
|
|
||||||
></paper-input>
|
|
||||||
<paper-input
|
|
||||||
value="{{_entityId}}"
|
|
||||||
label="[[localize('ui.dialogs.more_info_settings.entity_id')]]"
|
|
||||||
error-message="Domain needs to stay the same"
|
|
||||||
invalid="[[_computeInvalid(_entityId)]]"
|
|
||||||
></paper-input>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
hass: Object,
|
|
||||||
stateObj: Object,
|
|
||||||
|
|
||||||
registryInfo: {
|
|
||||||
type: Object,
|
|
||||||
observer: "_registryInfoChanged",
|
|
||||||
notify: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
_name: String,
|
|
||||||
_entityId: String,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeStateName(stateObj) {
|
|
||||||
if (!stateObj) return "";
|
|
||||||
return computeStateName(stateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeInvalid(entityId) {
|
|
||||||
return computeDomain(this.stateObj.entity_id) !== computeDomain(entityId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_registryInfoChanged(newVal) {
|
|
||||||
if (newVal) {
|
|
||||||
this.setProperties({
|
|
||||||
_name: newVal.name,
|
|
||||||
_entityId: newVal.entity_id,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setProperties({
|
|
||||||
_name: "",
|
|
||||||
_entityId: "",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_backTapped() {
|
|
||||||
this.fire("more-info-page", { page: null });
|
|
||||||
}
|
|
||||||
|
|
||||||
async _save() {
|
|
||||||
try {
|
|
||||||
const info = await updateEntityRegistryEntry(
|
|
||||||
this.hass,
|
|
||||||
this.stateObj.entity_id,
|
|
||||||
{
|
|
||||||
name: this._name,
|
|
||||||
new_entity_id: this._entityId,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
showSaveSuccessToast(this, this.hass);
|
|
||||||
|
|
||||||
this.registryInfo = info;
|
|
||||||
|
|
||||||
// Keep the more info dialog open at the new entity.
|
|
||||||
if (this.stateObj.entity_id !== this._entityId) {
|
|
||||||
this.fire("hass-more-info", { entityId: this._entityId });
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
alert(`save failed: ${err.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customElements.define("more-info-settings", MoreInfoSettings);
|
|
@ -1,206 +1,151 @@
|
|||||||
|
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||||
|
import "@polymer/paper-tabs/paper-tab";
|
||||||
|
import "@polymer/paper-tabs/paper-tabs";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import {
|
import {
|
||||||
LitElement,
|
|
||||||
html,
|
|
||||||
css,
|
css,
|
||||||
CSSResult,
|
CSSResult,
|
||||||
TemplateResult,
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
property,
|
property,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
import { cache } from "lit-html/directives/cache";
|
||||||
import "@polymer/paper-input/paper-input";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import "../../../components/dialog/ha-paper-dialog";
|
import "../../../components/dialog/ha-paper-dialog";
|
||||||
import "../../../components/ha-switch";
|
// tslint:disable-next-line: no-duplicate-imports
|
||||||
|
import { HaPaperDialog } from "../../../components/dialog/ha-paper-dialog";
|
||||||
import { EntityRegistryDetailDialogParams } from "./show-dialog-entity-registry-detail";
|
import "../../../components/ha-related-items";
|
||||||
|
import "../../../dialogs/more-info/controls/more-info-content";
|
||||||
import { PolymerChangedEvent } from "../../../polymer-types";
|
import { PolymerChangedEvent } from "../../../polymer-types";
|
||||||
import { haStyleDialog } from "../../../resources/styles";
|
import { haStyleDialog } from "../../../resources/styles";
|
||||||
|
import "../../../state-summary/state-card-content";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import "./entity-registry-settings";
|
||||||
// tslint:disable-next-line: no-duplicate-imports
|
import { EntityRegistryDetailDialogParams } from "./show-dialog-entity-registry-detail";
|
||||||
import { HaSwitch } from "../../../components/ha-switch";
|
|
||||||
|
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
@customElement("dialog-entity-registry-detail")
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
export class DialogEntityRegistryDetail extends LitElement {
|
||||||
import {
|
|
||||||
updateEntityRegistryEntry,
|
|
||||||
removeEntityRegistryEntry,
|
|
||||||
} from "../../../data/entity_registry";
|
|
||||||
import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation";
|
|
||||||
|
|
||||||
class DialogEntityRegistryDetail extends LitElement {
|
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
@property() private _name!: string;
|
|
||||||
@property() private _entityId!: string;
|
|
||||||
@property() private _disabledBy!: string | null;
|
|
||||||
@property() private _error?: string;
|
|
||||||
@property() private _params?: EntityRegistryDetailDialogParams;
|
@property() private _params?: EntityRegistryDetailDialogParams;
|
||||||
@property() private _submitting?: boolean;
|
@property() private _curTab?: string;
|
||||||
private _origEntityId!: string;
|
@query("ha-paper-dialog") private _dialog!: HaPaperDialog;
|
||||||
|
private _curTabIndex = 0;
|
||||||
|
|
||||||
public async showDialog(
|
public async showDialog(
|
||||||
params: EntityRegistryDetailDialogParams
|
params: EntityRegistryDetailDialogParams
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
this._params = params;
|
this._params = params;
|
||||||
this._error = undefined;
|
|
||||||
this._name = this._params.entry.name || "";
|
|
||||||
this._origEntityId = this._params.entry.entity_id;
|
|
||||||
this._entityId = this._params.entry.entity_id;
|
|
||||||
this._disabledBy = this._params.entry.disabled_by;
|
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public closeDialog(): void {
|
||||||
|
this._params = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
if (!this._params) {
|
if (!this._params) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
const entry = this._params.entry;
|
const entry = this._params.entry;
|
||||||
const stateObj: HassEntity | undefined = this.hass.states[entry.entity_id];
|
const stateObj: HassEntity | undefined = this.hass.states[entry.entity_id];
|
||||||
const invalidDomainUpdate =
|
|
||||||
computeDomain(this._entityId.trim()) !==
|
|
||||||
computeDomain(this._params.entry.entity_id);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-paper-dialog
|
<ha-paper-dialog
|
||||||
with-backdrop
|
with-backdrop
|
||||||
opened
|
opened
|
||||||
@opened-changed="${this._openedChanged}"
|
@opened-changed=${this._openedChanged}
|
||||||
>
|
>
|
||||||
<h2>
|
<app-toolbar>
|
||||||
|
<paper-icon-button
|
||||||
|
aria-label=${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.dialog.dismiss"
|
||||||
|
)}
|
||||||
|
icon="hass:close"
|
||||||
|
dialog-dismiss
|
||||||
|
></paper-icon-button>
|
||||||
|
<div class="main-title" main-title>
|
||||||
${stateObj
|
${stateObj
|
||||||
? computeStateName(stateObj)
|
? computeStateName(stateObj)
|
||||||
: entry.name || entry.entity_id}
|
: entry.name || entry.entity_id}
|
||||||
</h2>
|
</div>
|
||||||
|
${stateObj
|
||||||
|
? html`
|
||||||
|
<paper-icon-button
|
||||||
|
aria-label=${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.dialog.control"
|
||||||
|
)}
|
||||||
|
icon="hass:tune"
|
||||||
|
@click=${this._openMoreInfo}
|
||||||
|
></paper-icon-button>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</app-toolbar>
|
||||||
|
<paper-tabs
|
||||||
|
scrollable
|
||||||
|
hide-scroll-buttons
|
||||||
|
.selected=${this._curTabIndex}
|
||||||
|
@selected-item-changed=${this._handleTabSelected}
|
||||||
|
>
|
||||||
|
<paper-tab id="tab-settings">
|
||||||
|
${this.hass.localize("ui.panel.config.entities.dialog.settings")}
|
||||||
|
</paper-tab>
|
||||||
|
<paper-tab id="tab-related">
|
||||||
|
${this.hass.localize("ui.panel.config.entities.dialog.related")}
|
||||||
|
</paper-tab>
|
||||||
|
</paper-tabs>
|
||||||
|
${cache(
|
||||||
|
this._curTab === "tab-settings"
|
||||||
|
? html`
|
||||||
|
<entity-registry-settings
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entry=${entry}
|
||||||
|
.dialogElement=${this._dialog}
|
||||||
|
@close-dialog=${this._closeDialog}
|
||||||
|
></entity-registry-settings>
|
||||||
|
`
|
||||||
|
: this._curTab === "tab-related"
|
||||||
|
? html`
|
||||||
<paper-dialog-scrollable>
|
<paper-dialog-scrollable>
|
||||||
${!stateObj
|
<ha-related-items
|
||||||
? html`
|
.hass=${this.hass}
|
||||||
<div>
|
.itemId=${entry.entity_id}
|
||||||
${this.hass!.localize(
|
itemType="entity"
|
||||||
"ui.panel.config.entities.editor.unavailable"
|
@close-dialog=${this._closeDialog}
|
||||||
)}
|
></ha-related-items>
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._error
|
|
||||||
? html`
|
|
||||||
<div class="error">${this._error}</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<div class="form">
|
|
||||||
<paper-input
|
|
||||||
.value=${this._name}
|
|
||||||
@value-changed=${this._nameChanged}
|
|
||||||
.label=${this.hass.localize("ui.dialogs.more_info_settings.name")}
|
|
||||||
.placeholder=${stateObj ? computeStateName(stateObj) : ""}
|
|
||||||
.disabled=${this._submitting}
|
|
||||||
></paper-input>
|
|
||||||
<paper-input
|
|
||||||
.value=${this._entityId}
|
|
||||||
@value-changed=${this._entityIdChanged}
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.dialogs.more_info_settings.entity_id"
|
|
||||||
)}
|
|
||||||
error-message="Domain needs to stay the same"
|
|
||||||
.invalid=${invalidDomainUpdate}
|
|
||||||
.disabled=${this._submitting}
|
|
||||||
></paper-input>
|
|
||||||
<div class="row">
|
|
||||||
<ha-switch
|
|
||||||
.checked=${!this._disabledBy}
|
|
||||||
@change=${this._disabledByChanged}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.entities.editor.enabled_label"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div class="secondary">
|
|
||||||
${this._disabledBy && this._disabledBy !== "user"
|
|
||||||
? this.hass.localize(
|
|
||||||
"ui.panel.config.entities.editor.enabled_cause",
|
|
||||||
"cause",
|
|
||||||
this.hass.localize(
|
|
||||||
`config_entry.disabled_by.${this._disabledBy}`
|
|
||||||
)
|
|
||||||
)
|
|
||||||
: ""}
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.entities.editor.enabled_description"
|
|
||||||
)}
|
|
||||||
<br />${this.hass.localize(
|
|
||||||
"ui.panel.config.entities.editor.note"
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ha-switch>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</paper-dialog-scrollable>
|
</paper-dialog-scrollable>
|
||||||
<div class="paper-dialog-buttons">
|
`
|
||||||
<mwc-button
|
: html``
|
||||||
class="warning"
|
)}
|
||||||
@click="${this._confirmDeleteEntry}"
|
|
||||||
.disabled=${this._submitting ||
|
|
||||||
!(stateObj && stateObj.attributes.restored)}
|
|
||||||
>
|
|
||||||
${this.hass.localize("ui.panel.config.entities.editor.delete")}
|
|
||||||
</mwc-button>
|
|
||||||
<mwc-button
|
|
||||||
@click="${this._updateEntry}"
|
|
||||||
.disabled=${invalidDomainUpdate || this._submitting}
|
|
||||||
>
|
|
||||||
${this.hass.localize("ui.panel.config.entities.editor.update")}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-paper-dialog>
|
</ha-paper-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _nameChanged(ev: PolymerChangedEvent<string>): void {
|
private _handleTabSelected(ev: CustomEvent): void {
|
||||||
this._error = undefined;
|
if (!ev.detail.value) {
|
||||||
this._name = ev.detail.value;
|
return;
|
||||||
|
}
|
||||||
|
this._curTab = ev.detail.value.id;
|
||||||
|
this._resizeDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _entityIdChanged(ev: PolymerChangedEvent<string>): void {
|
private async _resizeDialog(): Promise<void> {
|
||||||
this._error = undefined;
|
await this.updateComplete;
|
||||||
this._entityId = ev.detail.value;
|
fireEvent(this._dialog as HTMLElement, "iron-resize");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _updateEntry(): Promise<void> {
|
private _openMoreInfo(): void {
|
||||||
this._submitting = true;
|
fireEvent(this, "hass-more-info", {
|
||||||
try {
|
entityId: this._params!.entry.entity_id,
|
||||||
await updateEntityRegistryEntry(this.hass!, this._origEntityId, {
|
|
||||||
name: this._name.trim() || null,
|
|
||||||
disabled_by: this._disabledBy,
|
|
||||||
new_entity_id: this._entityId.trim(),
|
|
||||||
});
|
});
|
||||||
this._params = undefined;
|
this._params = undefined;
|
||||||
} catch (err) {
|
|
||||||
this._error = err.message || "Unknown error";
|
|
||||||
} finally {
|
|
||||||
this._submitting = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _deleteEntry(): Promise<void> {
|
private _closeDialog(): void {
|
||||||
this._submitting = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await removeEntityRegistryEntry(this.hass!, this._entityId);
|
|
||||||
this._params = undefined;
|
this._params = undefined;
|
||||||
} finally {
|
|
||||||
this._submitting = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _confirmDeleteEntry(): void {
|
|
||||||
showConfirmationDialog(this, {
|
|
||||||
text: this.hass.localize(
|
|
||||||
"ui.panel.config.entities.editor.confirm_delete"
|
|
||||||
),
|
|
||||||
confirm: () => this._deleteEntry(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _openedChanged(ev: PolymerChangedEvent<boolean>): void {
|
private _openedChanged(ev: PolymerChangedEvent<boolean>): void {
|
||||||
@ -208,36 +153,88 @@ class DialogEntityRegistryDetail extends LitElement {
|
|||||||
this._params = undefined;
|
this._params = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _disabledByChanged(ev: Event): void {
|
|
||||||
this._disabledBy = (ev.target as HaSwitch).checked ? null : "user";
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
|
app-toolbar {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
background-color: var(--secondary-background-color);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-toolbar [main-title] {
|
||||||
|
/* Design guideline states 24px, changed to 16 to align with state info */
|
||||||
|
margin-left: 16px;
|
||||||
|
line-height: 1.3em;
|
||||||
|
max-height: 2.6em;
|
||||||
|
overflow: hidden;
|
||||||
|
/* webkit and blink still support simple multiline text-overflow */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width: 451px) and (min-height: 501px) {
|
||||||
|
.main-title {
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-paper-dialog {
|
||||||
|
width: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* overrule the ha-style-dialog max-height on small screens */
|
||||||
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
|
app-toolbar {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: var(--text-primary-color);
|
||||||
|
}
|
||||||
|
ha-paper-dialog {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
border-radius: 0px;
|
||||||
|
position: fixed !important;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
ha-paper-dialog::before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
z-index: -1;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paper-dialog-scrollable {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mwc-button.warning {
|
||||||
|
--mdc-theme-primary: var(--google-red-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([rtl]) app-toolbar {
|
||||||
|
direction: rtl;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
:host {
|
:host {
|
||||||
--paper-font-title_-_white-space: normal;
|
--paper-font-title_-_white-space: normal;
|
||||||
}
|
}
|
||||||
ha-paper-dialog {
|
paper-tabs {
|
||||||
min-width: 400px;
|
--paper-tabs-selection-bar-color: var(--primary-color);
|
||||||
max-width: 450px;
|
text-transform: uppercase;
|
||||||
}
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
.form {
|
margin-top: 0;
|
||||||
padding-bottom: 24px;
|
|
||||||
}
|
|
||||||
mwc-button.warning {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
.error {
|
|
||||||
color: var(--google-red-500);
|
|
||||||
}
|
|
||||||
.row {
|
|
||||||
margin-top: 8px;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
.secondary {
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
@ -249,8 +246,3 @@ declare global {
|
|||||||
"dialog-entity-registry-detail": DialogEntityRegistryDetail;
|
"dialog-entity-registry-detail": DialogEntityRegistryDetail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define(
|
|
||||||
"dialog-entity-registry-detail",
|
|
||||||
DialogEntityRegistryDetail
|
|
||||||
);
|
|
||||||
|
237
src/panels/config/entities/entity-registry-settings.ts
Normal file
237
src/panels/config/entities/entity-registry-settings.ts
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
import {
|
||||||
|
LitElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
TemplateResult,
|
||||||
|
property,
|
||||||
|
customElement,
|
||||||
|
PropertyValues,
|
||||||
|
} from "lit-element";
|
||||||
|
import "@polymer/paper-input/paper-input";
|
||||||
|
|
||||||
|
import "../../../components/ha-switch";
|
||||||
|
|
||||||
|
import { PolymerChangedEvent } from "../../../polymer-types";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
// tslint:disable-next-line: no-duplicate-imports
|
||||||
|
import { HaSwitch } from "../../../components/ha-switch";
|
||||||
|
|
||||||
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
|
import {
|
||||||
|
updateEntityRegistryEntry,
|
||||||
|
removeEntityRegistryEntry,
|
||||||
|
EntityRegistryEntry,
|
||||||
|
} from "../../../data/entity_registry";
|
||||||
|
import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation";
|
||||||
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
@customElement("entity-registry-settings")
|
||||||
|
export class EntityRegistrySettings extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
@property() public entry!: EntityRegistryEntry;
|
||||||
|
@property() public dialogElement!: HTMLElement;
|
||||||
|
@property() private _name!: string;
|
||||||
|
@property() private _entityId!: string;
|
||||||
|
@property() private _disabledBy!: string | null;
|
||||||
|
@property() private _error?: string;
|
||||||
|
@property() private _submitting?: boolean;
|
||||||
|
private _origEntityId!: string;
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues) {
|
||||||
|
if (changedProperties.has("entry")) {
|
||||||
|
this._error = undefined;
|
||||||
|
this._name = this.entry.name || "";
|
||||||
|
this._origEntityId = this.entry.entity_id;
|
||||||
|
this._entityId = this.entry.entity_id;
|
||||||
|
this._disabledBy = this.entry.disabled_by;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
if (this.entry.entity_id !== this._origEntityId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const stateObj: HassEntity | undefined = this.hass.states[
|
||||||
|
this.entry.entity_id
|
||||||
|
];
|
||||||
|
const invalidDomainUpdate =
|
||||||
|
computeDomain(this._entityId.trim()) !==
|
||||||
|
computeDomain(this.entry.entity_id);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<paper-dialog-scrollable .dialogElement=${this.dialogElement}>
|
||||||
|
${!stateObj
|
||||||
|
? html`
|
||||||
|
<div>
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.entities.editor.unavailable"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._error
|
||||||
|
? html`
|
||||||
|
<div class="error">${this._error}</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<div class="form">
|
||||||
|
<paper-input
|
||||||
|
.value=${this._name}
|
||||||
|
@value-changed=${this._nameChanged}
|
||||||
|
.label=${this.hass.localize("ui.panel.config.entities.editor.name")}
|
||||||
|
.placeholder=${stateObj ? computeStateName(stateObj) : ""}
|
||||||
|
.disabled=${this._submitting}
|
||||||
|
></paper-input>
|
||||||
|
<paper-input
|
||||||
|
.value=${this._entityId}
|
||||||
|
@value-changed=${this._entityIdChanged}
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.editor.entity_id"
|
||||||
|
)}
|
||||||
|
error-message="Domain needs to stay the same"
|
||||||
|
.invalid=${invalidDomainUpdate}
|
||||||
|
.disabled=${this._submitting}
|
||||||
|
></paper-input>
|
||||||
|
<div class="row">
|
||||||
|
<ha-switch
|
||||||
|
.checked=${!this._disabledBy}
|
||||||
|
@change=${this._disabledByChanged}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.editor.enabled_label"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div class="secondary">
|
||||||
|
${this._disabledBy && this._disabledBy !== "user"
|
||||||
|
? this.hass.localize(
|
||||||
|
"ui.panel.config.entities.editor.enabled_cause",
|
||||||
|
"cause",
|
||||||
|
this.hass.localize(
|
||||||
|
`config_entry.disabled_by.${this._disabledBy}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: ""}
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.editor.enabled_description"
|
||||||
|
)}
|
||||||
|
<br />${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.editor.note"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ha-switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog-scrollable>
|
||||||
|
<div class="buttons">
|
||||||
|
<mwc-button
|
||||||
|
class="warning"
|
||||||
|
@click="${this._confirmDeleteEntry}"
|
||||||
|
.disabled=${this._submitting ||
|
||||||
|
!(stateObj && stateObj.attributes.restored)}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.panel.config.entities.editor.delete")}
|
||||||
|
</mwc-button>
|
||||||
|
<mwc-button
|
||||||
|
@click="${this._updateEntry}"
|
||||||
|
.disabled=${invalidDomainUpdate || this._submitting}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.panel.config.entities.editor.update")}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _nameChanged(ev: PolymerChangedEvent<string>): void {
|
||||||
|
this._error = undefined;
|
||||||
|
this._name = ev.detail.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _entityIdChanged(ev: PolymerChangedEvent<string>): void {
|
||||||
|
this._error = undefined;
|
||||||
|
this._entityId = ev.detail.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _updateEntry(): Promise<void> {
|
||||||
|
this._submitting = true;
|
||||||
|
try {
|
||||||
|
await updateEntityRegistryEntry(this.hass!, this._origEntityId, {
|
||||||
|
name: this._name.trim() || null,
|
||||||
|
disabled_by: this._disabledBy,
|
||||||
|
new_entity_id: this._entityId.trim(),
|
||||||
|
});
|
||||||
|
fireEvent(this as HTMLElement, "close-dialog");
|
||||||
|
} catch (err) {
|
||||||
|
this._error = err.message || "Unknown error";
|
||||||
|
} finally {
|
||||||
|
this._submitting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _deleteEntry(): Promise<void> {
|
||||||
|
this._submitting = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await removeEntityRegistryEntry(this.hass!, this._entityId);
|
||||||
|
fireEvent(this as HTMLElement, "close-dialog");
|
||||||
|
} finally {
|
||||||
|
this._submitting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _confirmDeleteEntry(): void {
|
||||||
|
showConfirmationDialog(this, {
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.entities.editor.confirm_delete"
|
||||||
|
),
|
||||||
|
confirm: () => this._deleteEntry(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _disabledByChanged(ev: Event): void {
|
||||||
|
this._disabledBy = (ev.target as HaSwitch).checked ? null : "user";
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.form {
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
mwc-button.warning {
|
||||||
|
margin-right: auto;
|
||||||
|
--mdc-theme-primary: var(--google-red-500);
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: var(--google-red-500);
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
.secondary {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"entity-registry-settings": EntityRegistrySettings;
|
||||||
|
}
|
||||||
|
}
|
@ -46,9 +46,11 @@ import {
|
|||||||
DataTableColumnData,
|
DataTableColumnData,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation";
|
import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation";
|
||||||
|
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||||
|
import { DialogEntityRegistryDetail } from "./dialog-entity-registry-detail";
|
||||||
|
|
||||||
@customElement("ha-config-entities")
|
@customElement("ha-config-entities")
|
||||||
export class HaConfigEntities extends LitElement {
|
export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
@property() public isWide!: boolean;
|
@property() public isWide!: boolean;
|
||||||
@property() public narrow!: boolean;
|
@property() public narrow!: boolean;
|
||||||
@ -59,8 +61,6 @@ export class HaConfigEntities extends LitElement {
|
|||||||
@property() private _selectedEntities: string[] = [];
|
@property() private _selectedEntities: string[] = [];
|
||||||
@query("ha-data-table") private _dataTable!: HaDataTable;
|
@query("ha-data-table") private _dataTable!: HaDataTable;
|
||||||
|
|
||||||
private _unsubEntities?: UnsubscribeFunc;
|
|
||||||
|
|
||||||
private _columns = memoize(
|
private _columns = memoize(
|
||||||
(narrow, _language): DataTableColumnContainer => {
|
(narrow, _language): DataTableColumnContainer => {
|
||||||
const columns: DataTableColumnContainer = {
|
const columns: DataTableColumnContainer = {
|
||||||
@ -196,10 +196,23 @@ export class HaConfigEntities extends LitElement {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public hassSubscribe(): UnsubscribeFunc[] {
|
||||||
|
return [
|
||||||
|
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||||
|
this._entities = entities;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public disconnectedCallback() {
|
public disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
if (this._unsubEntities) {
|
const dialog = document
|
||||||
this._unsubEntities();
|
.querySelector("home-assistant")!
|
||||||
|
.shadowRoot!.querySelector("dialog-entity-registry-detail") as
|
||||||
|
| DialogEntityRegistryDetail
|
||||||
|
| undefined;
|
||||||
|
if (dialog) {
|
||||||
|
dialog.closeDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,18 +375,6 @@ export class HaConfigEntities extends LitElement {
|
|||||||
loadEntityRegistryDetailDialog();
|
loadEntityRegistryDetailDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps) {
|
|
||||||
super.updated(changedProps);
|
|
||||||
if (!this._unsubEntities) {
|
|
||||||
this._unsubEntities = subscribeEntityRegistry(
|
|
||||||
this.hass.connection,
|
|
||||||
(entities) => {
|
|
||||||
this._entities = entities;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _showDisabledChanged() {
|
private _showDisabledChanged() {
|
||||||
this._showDisabled = !this._showDisabled;
|
this._showDisabled = !this._showDisabled;
|
||||||
}
|
}
|
||||||
|
@ -553,6 +553,16 @@
|
|||||||
},
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Service"
|
"service": "Service"
|
||||||
|
},
|
||||||
|
"related-items": {
|
||||||
|
"integration": "Integration",
|
||||||
|
"device": "Device",
|
||||||
|
"area": "Area",
|
||||||
|
"entity": "Related entities",
|
||||||
|
"group": "Part of the following groups",
|
||||||
|
"scene": "Part of the following scenes",
|
||||||
|
"script": "Part of the following scripts",
|
||||||
|
"automation": "Part of the following automations"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dialogs": {
|
"dialogs": {
|
||||||
@ -593,12 +603,6 @@
|
|||||||
"confirm_remove_text": "Are you sure you want to remove this entity?"
|
"confirm_remove_text": "Are you sure you want to remove this entity?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"more_info_settings": {
|
|
||||||
"back": "Go back",
|
|
||||||
"save": "Save",
|
|
||||||
"name": "Name Override",
|
|
||||||
"entity_id": "Entity ID"
|
|
||||||
},
|
|
||||||
"options_flow": {
|
"options_flow": {
|
||||||
"form": {
|
"form": {
|
||||||
"header": "Options"
|
"header": "Options"
|
||||||
@ -1300,9 +1304,16 @@
|
|||||||
"confirm_text": "Entities can only be removed when the integration is no longer providing the entities."
|
"confirm_text": "Entities can only be removed when the integration is no longer providing the entities."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dialog": {
|
||||||
|
"settings": "Settings",
|
||||||
|
"control": "Control",
|
||||||
|
"related": "Related",
|
||||||
|
"dismiss": "Dismiss"
|
||||||
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
|
"name": "Name Override",
|
||||||
|
"entity_id": "Entity ID",
|
||||||
"unavailable": "This entity is not currently available.",
|
"unavailable": "This entity is not currently available.",
|
||||||
"default_name": "New Area",
|
|
||||||
"enabled_label": "Enable entity",
|
"enabled_label": "Enable entity",
|
||||||
"enabled_cause": "Disabled by {cause}.",
|
"enabled_cause": "Disabled by {cause}.",
|
||||||
"enabled_description": "Disabled entities will not be added to Home Assistant.",
|
"enabled_description": "Disabled entities will not be added to Home Assistant.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user