From 65994e7280576f4ee7be179c41b1b6dfacf30821 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 29 Jan 2020 00:13:44 +0100 Subject: [PATCH] Add related items to device info (#4637) * Add related items to device info * Update ha-config-device-page.ts * remove log * Lint * Fix dialog logic showing triggers on script dialog Co-authored-by: Paulus Schoutsen --- src/components/ha-chips.ts | 9 +- src/data/scene.ts | 17 + src/data/script.ts | 17 + .../ha-device-automation-card.ts | 32 +- .../ha-device-automation-dialog.ts | 184 +++++++++ .../devices/device-detail/ha-device-card.ts | 108 +++-- .../device-detail/ha-device-entities-card.ts | 183 ++++---- .../show-dialog-device-automation.ts | 22 + .../config/devices/ha-config-device-page.ts | 390 +++++++++++++----- src/panels/config/scene/ha-scene-editor.ts | 46 ++- src/panels/config/script/ha-script-editor.ts | 5 +- .../lovelace/cards/hui-entities-card.ts | 6 +- src/translations/en.json | 21 +- 13 files changed, 768 insertions(+), 272 deletions(-) create mode 100644 src/panels/config/devices/device-detail/ha-device-automation-dialog.ts create mode 100644 src/panels/config/devices/device-detail/show-dialog-device-automation.ts diff --git a/src/components/ha-chips.ts b/src/components/ha-chips.ts index 132fb1f99d..df2fe418c2 100644 --- a/src/components/ha-chips.ts +++ b/src/components/ha-chips.ts @@ -47,12 +47,9 @@ export class HaChips extends LitElement { } private _handleClick(ev) { - fireEvent( - this, - "chip-clicked", - { index: ev.target.closest("button").index }, - { bubbles: false } - ); + fireEvent(this, "chip-clicked", { + index: ev.target.closest("button").index, + }); } static get styles(): CSSResult { diff --git a/src/data/scene.ts b/src/data/scene.ts index 177b8dfbd8..6e3e65a66f 100644 --- a/src/data/scene.ts +++ b/src/data/scene.ts @@ -4,6 +4,7 @@ import { } from "home-assistant-js-websocket"; import { HomeAssistant, ServiceCallResponse } from "../types"; +import { navigate } from "../common/navigate"; export const SCENE_IGNORED_DOMAINS = [ "sensor", @@ -18,6 +19,22 @@ export const SCENE_IGNORED_DOMAINS = [ "zone", ]; +let inititialSceneEditorData: Partial | undefined; + +export const showSceneEditor = ( + el: HTMLElement, + data?: Partial +) => { + inititialSceneEditorData = data; + navigate(el, "/config/scene/edit/new"); +}; + +export const getSceneEditorInitData = () => { + const data = inititialSceneEditorData; + inititialSceneEditorData = undefined; + return data; +}; + export interface SceneEntity extends HassEntityBase { attributes: HassEntityAttributeBase & { id?: string }; } diff --git a/src/data/script.ts b/src/data/script.ts index 781ed79af5..c52979b664 100644 --- a/src/data/script.ts +++ b/src/data/script.ts @@ -5,6 +5,7 @@ import { HassEntityBase, HassEntityAttributeBase, } from "home-assistant-js-websocket"; +import { navigate } from "../common/navigate"; export interface ScriptEntity extends HassEntityBase { attributes: HassEntityAttributeBase & { @@ -65,3 +66,19 @@ export const triggerScript = ( export const deleteScript = (hass: HomeAssistant, objectId: string) => hass.callApi("DELETE", `config/script/config/${objectId}`); + +let inititialScriptEditorData: Partial | undefined; + +export const showScriptEditor = ( + el: HTMLElement, + data?: Partial +) => { + inititialScriptEditorData = data; + navigate(el, "/config/script/new"); +}; + +export const getScriptEditorInitData = () => { + const data = inititialScriptEditorData; + inititialScriptEditorData = undefined; + return data; +}; diff --git a/src/panels/config/devices/device-detail/ha-device-automation-card.ts b/src/panels/config/devices/device-detail/ha-device-automation-card.ts index 1cdbe5c6b9..1d512b68a6 100644 --- a/src/panels/config/devices/device-detail/ha-device-automation-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-automation-card.ts @@ -5,12 +5,14 @@ import { DeviceAutomation } from "../../../../data/device_automation"; import "../../../../components/ha-card"; import "../../../../components/ha-chips"; import { showAutomationEditor } from "../../../../data/automation"; +import { showScriptEditor } from "../../../../data/script"; export abstract class HaDeviceAutomationCard< T extends DeviceAutomation > extends LitElement { @property() public hass!: HomeAssistant; @property() public deviceId?: string; + @property() public script = false; @property() public automations: T[] = []; protected headerKey = ""; @@ -46,20 +48,18 @@ export abstract class HaDeviceAutomationCard< return html``; } return html` - -
- ${this.hass.localize(this.headerKey)} -
-
- - this._localizeDeviceAutomation(this.hass, automation) - )} - > - -
-
+

+ ${this.hass.localize(this.headerKey)} +

+
+ + this._localizeDeviceAutomation(this.hass, automation) + )} + > + +
`; } @@ -68,6 +68,10 @@ export abstract class HaDeviceAutomationCard< if (!automation) { return; } + if (this.script) { + showScriptEditor(this, { sequence: [automation] }); + return; + } const data = {}; data[this.type] = [automation]; showAutomationEditor(this, data); diff --git a/src/panels/config/devices/device-detail/ha-device-automation-dialog.ts b/src/panels/config/devices/device-detail/ha-device-automation-dialog.ts new file mode 100644 index 0000000000..d7409e3e4a --- /dev/null +++ b/src/panels/config/devices/device-detail/ha-device-automation-dialog.ts @@ -0,0 +1,184 @@ +import { + LitElement, + html, + css, + CSSResult, + TemplateResult, + property, + customElement, +} from "lit-element"; + +import "../../../../components/ha-dialog"; +import "./ha-device-triggers-card"; +import "./ha-device-conditions-card"; +import "./ha-device-actions-card"; +import { DeviceAutomationDialogParams } from "./show-dialog-device-automation"; +import { HomeAssistant } from "../../../../types"; +import { + DeviceTrigger, + DeviceCondition, + DeviceAction, + fetchDeviceTriggers, + fetchDeviceConditions, + fetchDeviceActions, +} from "../../../../data/device_automation"; + +@customElement("dialog-device-automation") +export class DialogDeviceAutomation extends LitElement { + @property() public hass!: HomeAssistant; + @property() private _triggers: DeviceTrigger[] = []; + @property() private _conditions: DeviceCondition[] = []; + @property() private _actions: DeviceAction[] = []; + @property() private _params?: DeviceAutomationDialogParams; + + public async showDialog(params: DeviceAutomationDialogParams): Promise { + this._params = params; + await this.updateComplete; + } + + protected updated(changedProps): void { + super.updated(changedProps); + + if (!changedProps.has("_params")) { + return; + } + + this._triggers = []; + this._conditions = []; + this._actions = []; + + if (!this._params) { + return; + } + + const { deviceId, script } = this._params; + + fetchDeviceActions(this.hass, deviceId).then( + (actions) => (this._actions = actions) + ); + if (script) { + return; + } + fetchDeviceTriggers(this.hass, deviceId).then( + (triggers) => (this._triggers = triggers) + ); + fetchDeviceConditions(this.hass, deviceId).then( + (conditions) => (this._conditions = conditions) + ); + } + + protected render(): TemplateResult | void { + if (!this._params) { + return html``; + } + + return html` + +
+ ${this._triggers.length || + this._conditions.length || + this._actions.length + ? html` + ${this._triggers.length + ? html` + + ` + : ""} + ${this._conditions.length + ? html` + + ` + : ""} + ${this._actions.length + ? html` + + ` + : ""} + ` + : html``} +
+ + Close + +
+ `; + } + + private _close(): void { + this._params = undefined; + } + + static get styles(): CSSResult[] { + return [ + css` + ha-dialog { + --mdc-dialog-title-ink-color: var(--primary-text-color); + --justify-action-buttons: space-between; + } + @media only screen and (min-width: 600px) { + ha-dialog { + --mdc-dialog-min-width: 600px; + } + } + .form { + padding-bottom: 24px; + } + .location { + display: flex; + } + .location > * { + flex-grow: 1; + min-width: 0; + } + .location > *:first-child { + margin-right: 4px; + } + .location > *:last-child { + margin-left: 4px; + } + ha-location-editor { + margin-top: 16px; + } + ha-user-picker { + margin-top: 16px; + } + mwc-button.warning { + --mdc-theme-primary: var(--google-red-500); + } + .error { + color: var(--google-red-500); + } + a { + color: var(--primary-color); + } + p { + color: var(--primary-text-color); + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-device-automation": DialogDeviceAutomation; + } +} diff --git a/src/panels/config/devices/device-detail/ha-device-card.ts b/src/panels/config/devices/device-detail/ha-device-card.ts index c0a40927e3..141e3389d2 100644 --- a/src/panels/config/devices/device-detail/ha-device-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-card.ts @@ -1,5 +1,3 @@ -import "../../../../components/ha-card"; - import { DeviceRegistryEntry, computeDeviceName, @@ -27,63 +25,63 @@ export class HaDeviceCard extends LitElement { protected render(): TemplateResult { return html` - -
-
-
${this.device.model}
- ${this.device.manufacturer - ? html` -
- ${this.hass.localize( - "ui.panel.config.integrations.config_entry.manuf", - "manufacturer", - this.device.manufacturer - )} -
- ` - : ""} - ${this.device.area_id - ? html` -
-
- ${this.hass.localize( - "ui.panel.config.integrations.config_entry.area", - "area", - this._computeArea(this.areas, this.device) - )} -
-
- ` - : ""} -
- ${this.device.via_device_id - ? html` +
+ ${this.device.model + ? html` +
${this.device.model}
+ ` + : ""} + ${this.device.manufacturer + ? html` +
+ ${this.hass.localize( + "ui.panel.config.integrations.config_entry.manuf", + "manufacturer", + this.device.manufacturer + )} +
+ ` + : ""} + ${this.device.area_id + ? html` +
${this.hass.localize( - "ui.panel.config.integrations.config_entry.via" - )} - ${this._computeDeviceName( - this.devices, - this.device.via_device_id - )} -
- ` - : ""} - ${this.device.sw_version - ? html` -
- ${this.hass.localize( - "ui.panel.config.integrations.config_entry.firmware", - "version", - this.device.sw_version + "ui.panel.config.integrations.config_entry.area", + "area", + this._computeArea(this.areas, this.device) )}
- ` - : ""} -
- +
+ ` + : ""} + ${this.device.via_device_id + ? html` +
+ ${this.hass.localize( + "ui.panel.config.integrations.config_entry.via" + )} + ${this._computeDeviceName( + this.devices, + this.device.via_device_id + )} +
+ ` + : ""} + ${this.device.sw_version + ? html` +
+ ${this.hass.localize( + "ui.panel.config.integrations.config_entry.firmware", + "version", + this.device.sw_version + )} +
+ ` + : ""} +
`; } diff --git a/src/panels/config/devices/device-detail/ha-device-entities-card.ts b/src/panels/config/devices/device-detail/ha-device-entities-card.ts index 878c9ef091..b8540b6309 100644 --- a/src/panels/config/devices/device-detail/ha-device-entities-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-entities-card.ts @@ -6,8 +6,9 @@ import { customElement, css, CSSResult, + queryAll, + PropertyValues, } from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; import { HomeAssistant } from "../../../../types"; @@ -19,15 +20,13 @@ import "@polymer/paper-item/paper-item-body"; import "../../../../components/ha-card"; import "../../../../components/ha-icon"; -import "../../../../components/ha-switch"; import { showEntityRegistryDetailDialog } from "../../entities/show-dialog-entity-registry-detail"; -import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; -// tslint:disable-next-line -import { HaSwitch } from "../../../../components/ha-switch"; import { EntityRegistryStateEntry } from "../ha-config-device-page"; import { addEntitiesToLovelaceView } from "../../../lovelace/editor/add-entities-to-view"; +import { createRowElement } from "../../../lovelace/create-element/create-row-element"; +import { LovelaceRow } from "../../../lovelace/entity-rows/types"; @customElement("ha-device-entities-card") export class HaDeviceEntitiesCard extends LitElement { @@ -36,66 +35,61 @@ export class HaDeviceEntitiesCard extends LitElement { @property() public entities!: EntityRegistryStateEntry[]; @property() public narrow!: boolean; @property() private _showDisabled = false; + @queryAll("#entities > *") private _entityRows?: LovelaceRow[]; + + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!changedProps.has("hass")) { + return; + } + this._entityRows?.forEach((element) => { + element.hass = this.hass; + }); + } protected render(): TemplateResult { + const disabledEntities: EntityRegistryStateEntry[] = []; return html` - - - ${this.hass.localize( - "ui.panel.config.entities.picker.filter.show_disabled" - )} - - + ${this.entities.length ? html` - ${this.entities.map((entry: EntityRegistryStateEntry) => { - if (!this._showDisabled && entry.disabled_by) { - return ""; - } - const stateObj = this.hass.states[entry.entity_id]; - return html` - - ${stateObj - ? html` - - ` - : html` - - `} - -
${entry.stateName}
-
${entry.entity_id}
-
-
- ${stateObj - ? html` - - ` - : ""} - -
-
- `; - })} +
+ ${this.entities.map((entry: EntityRegistryStateEntry) => { + if (entry.disabled_by) { + disabledEntities.push(entry); + return ""; + } + return this.hass.states[entry.entity_id] + ? this._renderEntity(entry) + : this._renderEntry(entry); + })} +
+ ${disabledEntities.length + ? !this._showDisabled + ? html` + + ` + : html` + ${disabledEntities.map((entry) => + this._renderEntry(entry) + )} + + ` + : ""}
${this.hass.localize( @@ -119,22 +113,48 @@ export class HaDeviceEntitiesCard extends LitElement { `; } - private _showDisabledChanged(ev: Event) { - this._showDisabled = (ev.target as HaSwitch).checked; + private _toggleShowDisabled() { + this._showDisabled = !this._showDisabled; } - private _openEditEntry(ev: MouseEvent): void { - const entry = (ev.currentTarget! as any).closest("paper-icon-item").entry; + private _renderEntity(entry: EntityRegistryStateEntry): TemplateResult { + const element = createRowElement({ entity: entry.entity_id }); + if (this.hass) { + element.hass = this.hass; + } + // @ts-ignore + element.entry = entry; + element.addEventListener("hass-more-info", (ev) => this._openEditEntry(ev)); + + return html` +
${element}
+ `; + } + + private _renderEntry(entry: EntityRegistryStateEntry): TemplateResult { + return html` + + + +
+ ${entry.stateName || entry.entity_id} +
+
+
+ `; + } + + private _openEditEntry(ev: Event): void { + ev.stopPropagation(); + const entry = (ev.currentTarget! as any).entry; showEntityRegistryDetailDialog(this, { entry, }); } - private _openMoreInfo(ev: MouseEvent) { - const entry = (ev.currentTarget! as any).closest("paper-icon-item").entry; - fireEvent(this, "hass-more-info", { entityId: entry.entity_id }); - } - private _addToLovelaceView(): void { addEntitiesToLovelaceView( this, @@ -158,11 +178,32 @@ export class HaDeviceEntitiesCard extends LitElement { .disabled-entry { color: var(--secondary-text-color); } - state-badge { + #entities > * { + margin: 8px; + } + paper-icon-item { + min-height: 40px; + padding: 0 8px; cursor: pointer; } - paper-icon-item:not(.disabled-entry) paper-item-body { + .name { + font-size: 14px; + } + button.show-more { + color: var(--primary-color); + text-align: left; cursor: pointer; + background: none; + border-width: initial; + border-style: none; + border-color: initial; + border-image: initial; + padding: 16px; + font: inherit; + } + button.show-more:focus { + outline: none; + text-decoration: underline; } `; } diff --git a/src/panels/config/devices/device-detail/show-dialog-device-automation.ts b/src/panels/config/devices/device-detail/show-dialog-device-automation.ts new file mode 100644 index 0000000000..5bd92b0a72 --- /dev/null +++ b/src/panels/config/devices/device-detail/show-dialog-device-automation.ts @@ -0,0 +1,22 @@ +import { fireEvent } from "../../../../common/dom/fire_event"; + +export interface DeviceAutomationDialogParams { + deviceId: string; + script?: boolean; +} + +export const loadDeviceAutomationDialog = () => + import( + /* webpackChunkName: "device-automation-dialog" */ "./ha-device-automation-dialog" + ); + +export const showDeviceAutomationDialog = ( + element: HTMLElement, + detailParams: DeviceAutomationDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-device-automation", + dialogImport: loadDeviceAutomationDialog, + dialogParams: detailParams, + }); +}; diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 336d4642ff..c278250d9c 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -9,14 +9,13 @@ import { import memoizeOne from "memoize-one"; +import "@polymer/paper-tooltip/paper-tooltip"; + import "../../../layouts/hass-tabs-subpage"; import "../../../layouts/hass-error-screen"; import "../ha-config-section"; import "./device-detail/ha-device-card"; -import "./device-detail/ha-device-triggers-card"; -import "./device-detail/ha-device-conditions-card"; -import "./device-detail/ha-device-actions-card"; import "./device-detail/ha-device-entities-card"; import { HomeAssistant, Route } from "../../../types"; import { ConfigEntry } from "../../../data/config_entries"; @@ -33,19 +32,15 @@ import { loadDeviceRegistryDetailDialog, showDeviceRegistryDetailDialog, } from "../../../dialogs/device-registry-detail/show-dialog-device-registry-detail"; - -import { - DeviceTrigger, - DeviceAction, - DeviceCondition, - fetchDeviceTriggers, - fetchDeviceConditions, - fetchDeviceActions, -} from "../../../data/device_automation"; +import "../../../components/ha-icon-next"; import { compare } from "../../../common/string/compare"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { createValidEntityId } from "../../../common/entity/valid_entity_id"; import { configSections } from "../ha-panel-config"; +import { RelatedResult, findRelated } from "../../../data/search"; +import { SceneEntities, showSceneEditor } from "../../../data/scene"; +import { navigate } from "../../../common/navigate"; +import { showDeviceAutomationDialog } from "./device-detail/show-dialog-device-automation"; export interface EntityRegistryStateEntry extends EntityRegistryEntry { stateName?: string; @@ -59,12 +54,11 @@ export class HaConfigDevicePage extends LitElement { @property() public entities!: EntityRegistryEntry[]; @property() public areas!: AreaRegistryEntry[]; @property() public deviceId!: string; - @property() public narrow!: boolean; + @property({ type: Boolean, reflect: true }) public narrow!: boolean; + @property() public isWide!: boolean; @property() public showAdvanced!: boolean; @property() public route!: Route; - @property() private _triggers: DeviceTrigger[] = []; - @property() private _conditions: DeviceCondition[] = []; - @property() private _actions: DeviceAction[] = []; + @property() private _related?: RelatedResult; private _device = memoizeOne( ( @@ -97,25 +91,10 @@ export class HaConfigDevicePage extends LitElement { loadDeviceRegistryDetailDialog(); } - protected updated(changedProps): void { + protected updated(changedProps) { super.updated(changedProps); - if (changedProps.has("deviceId")) { - if (this.deviceId) { - fetchDeviceTriggers(this.hass, this.deviceId).then( - (triggers) => (this._triggers = triggers) - ); - fetchDeviceConditions(this.hass, this.deviceId).then( - (conditions) => (this._conditions = conditions) - ); - fetchDeviceActions(this.hass, this.deviceId).then( - (actions) => (this._actions = actions) - ); - } else { - this._triggers = []; - this._conditions = []; - this._actions = []; - } + this._findRelated(); } } @@ -146,70 +125,176 @@ export class HaConfigDevicePage extends LitElement { icon="hass:settings" @click=${this._showSettings} > - - ${this.hass.localize("ui.panel.config.devices.info")} - - ${this.hass.localize("ui.panel.config.devices.details")} - - - ${entities.length - ? html` -
+
+
+
+

${device.name_by_user || device.name}

+ +
+ + ${ + entities.length + ? html` + + + ` + : html`` + } +
+
+
+ ${ + this._related?.automation?.length + ? this._related.automation.map((automation) => { + const state = this.hass.states[automation]; + return state + ? html` +
+ + + ${state.attributes.friendly_name || + automation} + + + + ${!state.attributes.id + ? html` + ${this.hass.localize( + "ui.panel.config.devices.cant_edit" + )} + + ` + : ""} +
+ ` + : ""; + }) + : html` + ${this.hass.localize( + "ui.panel.config.devices.automation.no_automations" + )} + ` + } +
+ ${this.hass.localize( - "ui.panel.config.devices.entities.entities" + "ui.panel.config.devices.automation.create" )} +
- - - ` - : html``} - ${this._triggers.length || - this._conditions.length || - this._actions.length - ? html` -
- ${this.hass.localize("ui.panel.config.devices.automations")} + +
+
+ ${ + this._related?.scene?.length + ? this._related.scene.map((scene) => { + const state = this.hass.states[scene]; + return state + ? html` +
+ + + ${state.attributes.friendly_name || scene} + + + + ${!state.attributes.id + ? html` + ${this.hass.localize( + "ui.panel.config.devices.cant_edit" + )} + + ` + : ""} +
+ ` + : ""; + }) + : html` + ${this.hass.localize( + "ui.panel.config.devices.scene.no_scenes" + )} + ` + } +
+ + ${this.hass.localize( + "ui.panel.config.devices.scene.create" + )}
- ${this._triggers.length - ? html` - - ` - : ""} - ${this._conditions.length - ? html` - - ` - : ""} - ${this._actions.length - ? html` - - ` - : ""} - ` - : html``} +
+ ${ + this._related?.script?.length + ? this._related.script.map((script) => { + const state = this.hass.states[script]; + return state + ? html` + + + ${state.attributes.friendly_name || script} + + + + ` + : ""; + }) + : html` + + ${this.hass.localize( + "ui.panel.config.devices.script.no_scripts" + )} + ` + } +
+ + ${this.hass.localize("ui.panel.config.devices.script.create")} + +
+
+
+
+
- - `; + `; } private _computeEntityName(entity) { @@ -220,6 +305,50 @@ export class HaConfigDevicePage extends LitElement { return state ? computeStateName(state) : null; } + private async _findRelated() { + this._related = await findRelated(this.hass, "device", this.deviceId); + } + + private _createScene() { + const entities: SceneEntities = {}; + this._entities(this.deviceId, this.entities).forEach((entity) => { + entities[entity.entity_id] = ""; + }); + showSceneEditor(this, { + entities, + }); + } + + private _openScene(ev: Event) { + const state = (ev.currentTarget as any).scene; + if (state.attributes.id) { + navigate(this, `/config/scene/edit/${state.attributes.id}`); + } + } + + private _openScript(ev: Event) { + const script = (ev.currentTarget as any).script; + navigate(this, `/config/script/edit/${script}`); + } + + private _openAutomation(ev: Event) { + const state = (ev.currentTarget as any).automation; + if (state.attributes.id) { + navigate(this, `/config/automation/edit/${state.attributes.id}`); + } + } + + private _showScriptDialog() { + showDeviceAutomationDialog(this, { deviceId: this.deviceId, script: true }); + } + + private _showAutomationDialog() { + showDeviceAutomationDialog(this, { + deviceId: this.deviceId, + script: false, + }); + } + private async _showSettings() { const device = this._device(this.deviceId, this.devices)!; showDeviceRegistryDetailDialog(this, { @@ -282,20 +411,81 @@ export class HaConfigDevicePage extends LitElement { static get styles(): CSSResult { return css` - .header { - font-family: var(--paper-font-display1_-_font-family); + .container { + display: flex; + flex-wrap: wrap; + margin: auto; + max-width: 1000px; + margin-top: 32px; + margin-bottom: 32px; + } + + .device-info { + padding: 16px; + } + + .show-more { + } + + h1 { + margin-top: 0; + font-family: var(--paper-font-headline_-_font-family); -webkit-font-smoothing: var( - --paper-font-display1_-_-webkit-font-smoothing + --paper-font-headline_-_-webkit-font-smoothing ); - font-size: var(--paper-font-display1_-_font-size); - font-weight: var(--paper-font-display1_-_font-weight); - letter-spacing: var(--paper-font-display1_-_letter-spacing); - line-height: var(--paper-font-display1_-_line-height); + font-size: var(--paper-font-headline_-_font-size); + font-weight: var(--paper-font-headline_-_font-weight); + letter-spacing: var(--paper-font-headline_-_letter-spacing); + line-height: var(--paper-font-headline_-_line-height); opacity: var(--dark-primary-opacity); } - ha-config-section *:last-child { - padding-bottom: 24px; + .left, + .column, + .fullwidth { + padding: 8px; + box-sizing: border-box; + } + + .left { + width: 33.33%; + padding-bottom: 0; + } + + .right { + width: 66.66%; + display: flex; + flex-wrap: wrap; + } + + .fullwidth { + width: 100%; + } + + .column { + width: 50%; + } + + .column > *:not(:first-child) { + margin-top: 16px; + } + + :host([narrow]) .left, + :host([narrow]) .right, + :host([narrow]) .column { + width: 100%; + } + + :host([narrow]) .container { + margin-top: 0; + } + + paper-item { + cursor: pointer; + } + + paper-item.no-link { + cursor: default; } `; } diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index d1b10ff3f5..f63dce96b9 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -39,6 +39,7 @@ import { SceneEntities, applyScene, activateScene, + getSceneEditorInitData, } from "../../../data/scene"; import { fireEvent } from "../../../common/dom/fire_event"; import { @@ -391,6 +392,7 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) { super.updated(changedProps); const oldscene = changedProps.get("scene") as SceneEntity; + if ( changedProps.has("scene") && this.scene && @@ -403,10 +405,16 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) { if (changedProps.has("creatingNew") && this.creatingNew && this.hass) { this._dirty = false; + const initData = getSceneEditorInitData(); this._config = { name: this.hass.localize("ui.panel.config.scene.editor.default_name"), entities: {}, + ...initData, }; + if (initData) { + this._initEntities(this._config); + this._dirty = true; + } } if (changedProps.has("_entityRegistryEntries")) { @@ -458,24 +466,7 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) { config.entities = {}; } - this._entities = Object.keys(config.entities); - - this._entities.forEach((entity) => { - this._storeState(entity); - }); - - const filteredEntityReg = this._entityRegistryEntries.filter((entityReg) => - this._entities.includes(entityReg.entity_id) - ); - - for (const entityReg of filteredEntityReg) { - if (!entityReg.device_id) { - continue; - } - if (!this._devices.includes(entityReg.device_id)) { - this._devices = [...this._devices, entityReg.device_id]; - } - } + this._initEntities(config); const { context } = await activateScene(this.hass, this.scene!.entity_id); @@ -489,6 +480,25 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) { this._config = config; } + private _initEntities(config: SceneConfig) { + this._entities = Object.keys(config.entities); + this._entities.forEach((entity) => this._storeState(entity)); + + const filteredEntityReg = this._entityRegistryEntries.filter((entityReg) => + this._entities.includes(entityReg.entity_id) + ); + this._devices = []; + + for (const entityReg of filteredEntityReg) { + if (!entityReg.device_id) { + continue; + } + if (!this._devices.includes(entityReg.device_id)) { + this._devices = [...this._devices, entityReg.device_id]; + } + } + } + private _entityPicked(ev: CustomEvent) { const entityId = ev.detail.value; (ev.target as any).value = ""; diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index 3dcd615c03..b6134d7de3 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -20,6 +20,7 @@ import { ScriptEntity, ScriptConfig, deleteScript, + getScriptEditorInitData, } from "../../../data/script"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/ha-app-layout"; @@ -188,10 +189,12 @@ export class HaScriptEditor extends LitElement { } if (changedProps.has("creatingNew") && this.creatingNew && this.hass) { - this._dirty = false; + const initData = getScriptEditorInitData(); + this._dirty = initData ? true : false; this._config = { alias: this.hass.localize("ui.panel.config.script.editor.default_name"), sequence: [{ service: "" }], + ...initData, }; } } diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index 688769e54e..2f6dea1af7 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -39,11 +39,11 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { return { entities: [] }; } - @property() protected _config?: EntitiesCardConfig; + @property() private _config?: EntitiesCardConfig; - protected _hass?: HomeAssistant; + private _hass?: HomeAssistant; - protected _configEntities?: EntitiesCardEntityConfig[]; + private _configEntities?: EntitiesCardEntityConfig[]; set hass(hass: HomeAssistant) { this._hass = hass; diff --git a/src/translations/en.json b/src/translations/en.json index 9a3ca7ac1e..02f233872a 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1271,6 +1271,9 @@ "name": "Name", "update": "Update", "automation": { + "automations": "Automations", + "no_automations": "No automations", + "create": "Create automation with device", "triggers": { "caption": "Do something when..." }, @@ -1281,15 +1284,25 @@ "caption": "When something is triggered..." } }, + "script": { + "scripts": "Scripts", + "no_scripts": "No scripts", + "create": "Create script with device" + }, + "scene": { + "scenes": "Scenes", + "no_scenes": "No scenes", + "create": "Create scene with device" + }, + "cant_edit": "You can only edit items that are created in the UI.", "device_not_found": "Device not found.", - "info": "Device info", - "details": "Here are all the details of your device.", "entities": { "entities": "Entities", - "add_entities_lovelace": "Add all device entities to Lovelace UI", + "add_entities_lovelace": "Add to Lovelace", "none": "This device has no entities" }, - "automations": "Automations", + "scripts": "Scripts", + "scenes": "Scenes", "confirm_rename_entity_ids": "Do you also want to rename the entity id's of your entities?", "data_table": { "device": "Device",