mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-29 04:06:35 +00:00
commit
4e6d00cf5c
12
package.json
12
package.json
@ -17,9 +17,9 @@
|
||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@material/mwc-button": "^0.3.6",
|
||||
"@material/mwc-ripple": "^0.3.6",
|
||||
"@mdi/svg": "^3.0.39",
|
||||
"@material/mwc-button": "^0.5.0",
|
||||
"@material/mwc-ripple": "^0.5.0",
|
||||
"@mdi/svg": "3.5.95",
|
||||
"@polymer/app-layout": "^3.0.1",
|
||||
"@polymer/app-localize-behavior": "^3.0.1",
|
||||
"@polymer/app-route": "^3.0.2",
|
||||
@ -34,6 +34,7 @@
|
||||
"@polymer/iron-input": "^3.0.1",
|
||||
"@polymer/iron-label": "^3.0.1",
|
||||
"@polymer/iron-media-query": "^3.0.1",
|
||||
"@polymer/iron-overlay-behavior": "^3.0.2",
|
||||
"@polymer/iron-pages": "^3.0.1",
|
||||
"@polymer/iron-resizable-behavior": "^3.0.1",
|
||||
"@polymer/neon-animation": "^3.0.1",
|
||||
@ -79,7 +80,7 @@
|
||||
"jquery": "^3.3.1",
|
||||
"js-yaml": "^3.12.0",
|
||||
"leaflet": "^1.3.4",
|
||||
"lit-element": "^2.0.0",
|
||||
"lit-element": "^2.1.0",
|
||||
"lit-html": "^1.0.0",
|
||||
"marked": "^0.6.0",
|
||||
"mdn-polyfills": "^5.12.0",
|
||||
@ -167,7 +168,8 @@
|
||||
"@webcomponents/webcomponentsjs": "^2.2.6",
|
||||
"@webcomponents/shadycss": "^1.9.0",
|
||||
"@vaadin/vaadin-overlay": "3.2.2",
|
||||
"@vaadin/vaadin-lumo-styles": "1.3.0"
|
||||
"@vaadin/vaadin-lumo-styles": "1.3.0",
|
||||
"@polymer/iron-overlay-behavior": "^3.0.2"
|
||||
},
|
||||
"main": "src/home-assistant.js",
|
||||
"husky": {
|
||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20190321.0",
|
||||
version="20190327.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@ -2,6 +2,7 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "@material/mwc-button";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import "../components/ha-form";
|
||||
import "../components/ha-markdown";
|
||||
import { localizeLiteMixin } from "../mixins/localize-lite-mixin";
|
||||
|
||||
class HaAuthFlow extends localizeLiteMixin(PolymerElement) {
|
||||
@ -121,6 +122,12 @@ class HaAuthFlow extends localizeLiteMixin(PolymerElement) {
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
// allow auth provider bypass the login form
|
||||
if (data.type === "create_entry") {
|
||||
this._redirect(data.result);
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateStep(data);
|
||||
} else {
|
||||
this.setProperties({
|
||||
@ -138,6 +145,24 @@ class HaAuthFlow extends localizeLiteMixin(PolymerElement) {
|
||||
}
|
||||
}
|
||||
|
||||
_redirect(authCode) {
|
||||
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
|
||||
let url = this.redirectUri;
|
||||
if (!url.includes("?")) {
|
||||
url += "?";
|
||||
} else if (!url.endsWith("&")) {
|
||||
url += "&";
|
||||
}
|
||||
|
||||
url += `code=${encodeURIComponent(authCode)}`;
|
||||
|
||||
if (this.oauth2State) {
|
||||
url += `&state=${encodeURIComponent(this.oauth2State)}`;
|
||||
}
|
||||
|
||||
document.location = url;
|
||||
}
|
||||
|
||||
_updateStep(step) {
|
||||
const props = {
|
||||
_step: step,
|
||||
@ -229,21 +254,7 @@ class HaAuthFlow extends localizeLiteMixin(PolymerElement) {
|
||||
const newStep = await response.json();
|
||||
|
||||
if (newStep.type === "create_entry") {
|
||||
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
|
||||
let url = this.redirectUri;
|
||||
if (!url.includes("?")) {
|
||||
url += "?";
|
||||
} else if (!url.endsWith("&")) {
|
||||
url += "&";
|
||||
}
|
||||
|
||||
url += `code=${encodeURIComponent(newStep.result)}`;
|
||||
|
||||
if (this.oauth2State) {
|
||||
url += `&state=${encodeURIComponent(this.oauth2State)}`;
|
||||
}
|
||||
|
||||
document.location = url;
|
||||
this._redirect(newStep.result);
|
||||
return;
|
||||
}
|
||||
this._updateStep(newStep);
|
||||
|
@ -132,6 +132,10 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.playback-controls {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
paper-icon-button {
|
||||
opacity: var(--dark-primary-opacity);
|
||||
}
|
||||
@ -186,7 +190,7 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
class="self-center secondary"
|
||||
></paper-icon-button>
|
||||
|
||||
<div>
|
||||
<div class="playback-controls">
|
||||
<paper-icon-button
|
||||
icon="hass:skip-previous"
|
||||
invisible$="[[!playerObj.supportsPreviousTrack]]"
|
||||
|
@ -2,11 +2,17 @@ import {
|
||||
LitElement,
|
||||
html,
|
||||
PropertyValues,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
property,
|
||||
} from "lit-element";
|
||||
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
import computeStateDomain from "../../common/entity/compute_state_domain";
|
||||
import computeStateName from "../../common/entity/compute_state_name";
|
||||
@ -14,21 +20,20 @@ import domainIcon from "../../common/entity/domain_icon";
|
||||
import stateIcon from "../../common/entity/state_icon";
|
||||
import timerTimeRemaining from "../../common/entity/timer_time_remaining";
|
||||
import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
import "../ha-label-badge";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
* @appliesMixin EventsMixin
|
||||
*/
|
||||
@customElement("ha-state-label-badge")
|
||||
export class HaStateLabelBadge extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public state?: HassEntity;
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() public state?: HassEntity;
|
||||
|
||||
@property() private _timerTimeRemaining?: number;
|
||||
|
||||
private _connected?: boolean;
|
||||
|
||||
private _updateRemaining?: number;
|
||||
private _timerTimeRemaining?: number;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
@ -47,15 +52,20 @@ export class HaStateLabelBadge extends LitElement {
|
||||
|
||||
if (!state) {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-label-badge label="not found"></ha-label-badge>
|
||||
<ha-label-badge
|
||||
class="warning"
|
||||
label="${this.hass!.localize("state_badge.default.error")}"
|
||||
icon="hass:alert"
|
||||
description="${this.hass!.localize(
|
||||
"state_badge.default.entity_not_found"
|
||||
)}"
|
||||
></ha-label-badge>
|
||||
`;
|
||||
}
|
||||
|
||||
const domain = computeStateDomain(state);
|
||||
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-label-badge
|
||||
class="${classMap({
|
||||
[domain]: true,
|
||||
@ -70,14 +80,6 @@ export class HaStateLabelBadge extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
state: {},
|
||||
_timerTimeRemaining: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener("click", (ev) => {
|
||||
@ -201,48 +203,47 @@ export class HaStateLabelBadge extends LitElement {
|
||||
this._timerTimeRemaining = timerTimeRemaining(stateObj);
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
cursor: pointer;
|
||||
}
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
:host {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ha-label-badge {
|
||||
--ha-label-badge-color: var(--label-badge-red, #df4c1e);
|
||||
}
|
||||
ha-label-badge.has-unit_of_measurement {
|
||||
--ha-label-badge-label-text-transform: none;
|
||||
}
|
||||
ha-label-badge {
|
||||
--ha-label-badge-color: var(--label-badge-red, #df4c1e);
|
||||
}
|
||||
ha-label-badge.has-unit_of_measurement {
|
||||
--ha-label-badge-label-text-transform: none;
|
||||
}
|
||||
|
||||
ha-label-badge.binary_sensor,
|
||||
ha-label-badge.updater {
|
||||
--ha-label-badge-color: var(--label-badge-blue, #039be5);
|
||||
}
|
||||
ha-label-badge.binary_sensor,
|
||||
ha-label-badge.updater {
|
||||
--ha-label-badge-color: var(--label-badge-blue, #039be5);
|
||||
}
|
||||
|
||||
.red {
|
||||
--ha-label-badge-color: var(--label-badge-red, #df4c1e);
|
||||
}
|
||||
.red {
|
||||
--ha-label-badge-color: var(--label-badge-red, #df4c1e);
|
||||
}
|
||||
|
||||
.blue {
|
||||
--ha-label-badge-color: var(--label-badge-blue, #039be5);
|
||||
}
|
||||
.blue {
|
||||
--ha-label-badge-color: var(--label-badge-blue, #039be5);
|
||||
}
|
||||
|
||||
.green {
|
||||
--ha-label-badge-color: var(--label-badge-green, #0da035);
|
||||
}
|
||||
.green {
|
||||
--ha-label-badge-color: var(--label-badge-green, #0da035);
|
||||
}
|
||||
|
||||
.yellow {
|
||||
--ha-label-badge-color: var(--label-badge-yellow, #f4b400);
|
||||
}
|
||||
.yellow {
|
||||
--ha-label-badge-color: var(--label-badge-yellow, #f4b400);
|
||||
}
|
||||
|
||||
.grey {
|
||||
--ha-label-badge-color: var(
|
||||
--label-badge-grey,
|
||||
var(--paper-grey-500)
|
||||
);
|
||||
}
|
||||
</style>
|
||||
.grey {
|
||||
--ha-label-badge-color: var(--label-badge-grey, var(--paper-grey-500));
|
||||
}
|
||||
|
||||
.warning {
|
||||
--ha-label-badge-color: var(--label-badge-yellow, #fce588);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
@ -252,5 +253,3 @@ declare global {
|
||||
"ha-state-label-badge": HaStateLabelBadge;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-state-label-badge", HaStateLabelBadge);
|
||||
|
@ -25,6 +25,7 @@ class HaClimateControl extends EventsMixin(PolymerElement) {
|
||||
#target_temperature {
|
||||
@apply --layout-self-center;
|
||||
font-size: 200%;
|
||||
direction: ltr;
|
||||
}
|
||||
.control-buttons {
|
||||
font-size: 200%;
|
||||
|
@ -29,18 +29,24 @@ class HaClimateState extends LocalizeMixin(PolymerElement) {
|
||||
font-weight: bold;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.unit {
|
||||
display: inline-block;
|
||||
direction: ltr;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="target">
|
||||
<template is="dom-if" if="[[_hasKnownState(stateObj.state)]]">
|
||||
<span class="state-label"> [[_localizeState(stateObj.state)]] </span>
|
||||
</template>
|
||||
[[computeTarget(hass, stateObj)]]
|
||||
<div class="unit">[[computeTarget(hass, stateObj)]]</div>
|
||||
</div>
|
||||
|
||||
<template is="dom-if" if="[[currentStatus]]">
|
||||
<div class="current">
|
||||
[[localize('ui.card.climate.currently')]]: [[currentStatus]]
|
||||
[[localize('ui.card.climate.currently')]]:
|
||||
<div class="unit">[[currentStatus]]</div>
|
||||
</div>
|
||||
</template>
|
||||
`;
|
||||
|
@ -58,6 +58,11 @@ class HaPaperSlider extends PaperSliderClass {
|
||||
-webkit-transform: scale(1) translate(0, -10px);
|
||||
transform: scale(1) translate(0, -10px);
|
||||
}
|
||||
|
||||
:host([dir="rtl"]) .pin.expand > .slider-knob > .slider-knob-inner::after {
|
||||
-webkit-transform: scale(1) translate(0, -17px) scaleX(-1) !important;
|
||||
transform: scale(1) translate(0, -17px) scaleX(-1) !important;
|
||||
}
|
||||
`;
|
||||
tpl.content.appendChild(styleEl);
|
||||
return tpl;
|
||||
|
@ -26,19 +26,13 @@ const computePanels = (hass: HomeAssistant) => {
|
||||
if (!panels) {
|
||||
return [];
|
||||
}
|
||||
const isAdmin = hass.user.is_admin;
|
||||
|
||||
const sortValue = {
|
||||
map: 1,
|
||||
logbook: 2,
|
||||
history: 3,
|
||||
};
|
||||
const result: Panel[] = [];
|
||||
|
||||
Object.values(panels).forEach((panel) => {
|
||||
if (panel.title && (panel.component_name !== "config" || isAdmin)) {
|
||||
result.push(panel);
|
||||
}
|
||||
});
|
||||
const result: Panel[] = Object.values(panels).filter((panel) => panel.title);
|
||||
|
||||
result.sort((a, b) => {
|
||||
const aBuiltIn = a.component_name in sortValue;
|
||||
@ -133,9 +127,8 @@ class HaSidebar extends LitElement {
|
||||
: html``}
|
||||
</paper-listbox>
|
||||
|
||||
${!hass.user.is_admin
|
||||
? ""
|
||||
: html`
|
||||
${hass.user && hass.user.is_admin
|
||||
? html`
|
||||
<div>
|
||||
<div class="divider"></div>
|
||||
|
||||
@ -192,7 +185,8 @@ class HaSidebar extends LitElement {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
`
|
||||
: ""}
|
||||
`;
|
||||
}
|
||||
|
||||
|
8
src/data/panel_custom.ts
Normal file
8
src/data/panel_custom.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface CustomPanelConfig {
|
||||
name: string;
|
||||
embed_iframe: boolean;
|
||||
trust_external: boolean;
|
||||
js_url?: string;
|
||||
module_url?: string;
|
||||
html_url?: string;
|
||||
}
|
@ -16,6 +16,7 @@ export interface ZHADevice {
|
||||
manufacturer_code: number;
|
||||
device_reg_id: string;
|
||||
user_given_name: string;
|
||||
area_id: string;
|
||||
}
|
||||
|
||||
export interface Attribute {
|
||||
@ -42,7 +43,7 @@ export interface ReadAttributeServiceData {
|
||||
cluster_id: number;
|
||||
cluster_type: string;
|
||||
attribute: number;
|
||||
manufacturer: number;
|
||||
manufacturer?: number;
|
||||
}
|
||||
|
||||
export const reconfigureNode = (
|
||||
|
@ -17,6 +17,7 @@ import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
|
||||
import EventsMixin from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
@ -84,6 +85,7 @@ class MoreInfoClimate extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
width: 90px;
|
||||
font-size: 200%;
|
||||
margin: auto;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
ha-climate-control.range-control-left,
|
||||
@ -181,6 +183,7 @@ class MoreInfoClimate extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
value="[[stateObj.attributes.humidity]]"
|
||||
on-change="targetHumiditySliderChanged"
|
||||
ignore-bar-touch=""
|
||||
dir="[[rtl]]"
|
||||
>
|
||||
</ha-paper-slider>
|
||||
</div>
|
||||
@ -314,6 +317,12 @@ class MoreInfoClimate extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
awayToggleChecked: Boolean,
|
||||
auxToggleChecked: Boolean,
|
||||
onToggleChecked: Boolean,
|
||||
|
||||
rtl: {
|
||||
type: String,
|
||||
value: "ltr",
|
||||
computed: "_computeRTLDirection(hass)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -557,6 +566,10 @@ class MoreInfoClimate extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
_localizeFanMode(localize, mode) {
|
||||
return localize(`state_attributes.climate.fan_mode.${mode}`) || mode;
|
||||
}
|
||||
|
||||
_computeRTLDirection(hass) {
|
||||
return computeRTLDirection(hass);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("more-info-climate", MoreInfoClimate);
|
||||
|
@ -14,6 +14,7 @@ import attributeClassNames from "../../../common/entity/attribute_class_names";
|
||||
import isComponentLoaded from "../../../common/config/is_component_loaded";
|
||||
import EventsMixin from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
@ -137,6 +138,7 @@ class MoreInfoMediaPlayer extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
on-change="volumeSliderChanged"
|
||||
class="flex"
|
||||
ignore-bar-touch=""
|
||||
dir="{{rtl}}"
|
||||
>
|
||||
</ha-paper-slider>
|
||||
</div>
|
||||
@ -233,6 +235,11 @@ class MoreInfoMediaPlayer extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
|
||||
rtl: {
|
||||
type: String,
|
||||
computed: "_computeRTLDirection(hass)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -425,6 +432,10 @@ class MoreInfoMediaPlayer extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
this.ttsMessage = "";
|
||||
this.$.ttsInput.focus();
|
||||
}
|
||||
|
||||
_computeRTLDirection(hass) {
|
||||
return computeRTLDirection(hass);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("more-info-media_player", MoreInfoMediaPlayer);
|
||||
|
@ -1,80 +0,0 @@
|
||||
import { loadJS } from "../common/dom/load_resource";
|
||||
import loadCustomPanel from "../util/custom-panel/load-custom-panel";
|
||||
import createCustomPanelElement from "../util/custom-panel/create-custom-panel-element";
|
||||
import setCustomPanelProperties from "../util/custom-panel/set-custom-panel-properties";
|
||||
|
||||
const webComponentsSupported =
|
||||
"customElements" in window &&
|
||||
"import" in document.createElement("link") &&
|
||||
"content" in document.createElement("template");
|
||||
|
||||
let es5Loaded = null;
|
||||
|
||||
window.loadES5Adapter = () => {
|
||||
if (!es5Loaded) {
|
||||
es5Loaded = Promise.all([
|
||||
loadJS(`${__STATIC_PATH__}custom-elements-es5-adapter.js`).catch(),
|
||||
import(/* webpackChunkName: "compat" */ "./compatibility"),
|
||||
]);
|
||||
}
|
||||
return es5Loaded;
|
||||
};
|
||||
|
||||
let root = null;
|
||||
|
||||
function setProperties(properties) {
|
||||
if (root === null) return;
|
||||
setCustomPanelProperties(root, properties);
|
||||
}
|
||||
|
||||
function initialize(panel, properties) {
|
||||
const style = document.createElement("style");
|
||||
style.innerHTML = "body{margin:0}";
|
||||
document.head.appendChild(style);
|
||||
|
||||
const config = panel.config._panel_custom;
|
||||
let start = Promise.resolve();
|
||||
|
||||
if (!webComponentsSupported) {
|
||||
start = start.then(() => loadJS("/static/webcomponents-bundle.js"));
|
||||
}
|
||||
|
||||
if (__BUILD__ === "es5") {
|
||||
// Load ES5 adapter. Swallow errors as it raises errors on old browsers.
|
||||
start = start.then(() => window.loadES5Adapter());
|
||||
}
|
||||
|
||||
start
|
||||
.then(() => loadCustomPanel(config))
|
||||
// If our element is using es5, let it finish loading that and define element
|
||||
// This avoids elements getting upgraded after being added to the DOM
|
||||
.then(() => es5Loaded || Promise.resolve())
|
||||
.then(
|
||||
() => {
|
||||
root = createCustomPanelElement(config);
|
||||
|
||||
const forwardEvent = (ev) =>
|
||||
window.parent.customPanel.fire(ev.type, ev.detail);
|
||||
root.addEventListener("hass-toggle-menu", forwardEvent);
|
||||
window.addEventListener("location-changed", (ev) =>
|
||||
window.parent.customPanel.navigate(
|
||||
window.location.pathname,
|
||||
ev.detail ? ev.detail.replace : false
|
||||
)
|
||||
);
|
||||
setProperties(Object.assign({ panel }, properties));
|
||||
document.body.appendChild(root);
|
||||
},
|
||||
(err) => {
|
||||
// eslint-disable-next-line
|
||||
console.error(err, panel);
|
||||
alert(`Unable to load the panel source: ${err}.`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
() => window.parent.customPanel.registerIframe(initialize, setProperties),
|
||||
{ once: true }
|
||||
);
|
97
src/entrypoints/custom-panel.ts
Normal file
97
src/entrypoints/custom-panel.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import { loadJS } from "../common/dom/load_resource";
|
||||
import { loadCustomPanel } from "../util/custom-panel/load-custom-panel";
|
||||
import { createCustomPanelElement } from "../util/custom-panel/create-custom-panel-element";
|
||||
import { setCustomPanelProperties } from "../util/custom-panel/set-custom-panel-properties";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { navigate } from "../common/navigate";
|
||||
import { PolymerElement } from "@polymer/polymer";
|
||||
import { Panel } from "../types";
|
||||
import { CustomPanelConfig } from "../data/panel_custom";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
loadES5Adapter: () => Promise<unknown>;
|
||||
}
|
||||
}
|
||||
|
||||
const webComponentsSupported =
|
||||
"customElements" in window &&
|
||||
"import" in document.createElement("link") &&
|
||||
"content" in document.createElement("template");
|
||||
|
||||
let es5Loaded: Promise<unknown> | undefined;
|
||||
|
||||
window.loadES5Adapter = () => {
|
||||
if (!es5Loaded) {
|
||||
es5Loaded = Promise.all([
|
||||
loadJS(`${__STATIC_PATH__}custom-elements-es5-adapter.js`).catch(),
|
||||
import(/* webpackChunkName: "compat" */ "./compatibility"),
|
||||
]);
|
||||
}
|
||||
return es5Loaded;
|
||||
};
|
||||
|
||||
let panelEl: HTMLElement | PolymerElement | undefined;
|
||||
|
||||
function setProperties(properties) {
|
||||
if (!panelEl) {
|
||||
return;
|
||||
}
|
||||
setCustomPanelProperties(panelEl, properties);
|
||||
}
|
||||
|
||||
function initialize(panel: Panel, properties: {}) {
|
||||
const style = document.createElement("style");
|
||||
style.innerHTML = "body{margin:0}";
|
||||
document.head.appendChild(style);
|
||||
|
||||
const config = panel.config!._panel_custom as CustomPanelConfig;
|
||||
let start: Promise<unknown> = Promise.resolve();
|
||||
|
||||
if (!webComponentsSupported) {
|
||||
start = start.then(() => loadJS("/static/webcomponents-bundle.js"));
|
||||
}
|
||||
|
||||
if (__BUILD__ === "es5") {
|
||||
// Load ES5 adapter. Swallow errors as it raises errors on old browsers.
|
||||
start = start.then(() => window.loadES5Adapter());
|
||||
}
|
||||
|
||||
start
|
||||
.then(() => loadCustomPanel(config))
|
||||
// If our element is using es5, let it finish loading that and define element
|
||||
// This avoids elements getting upgraded after being added to the DOM
|
||||
.then(() => es5Loaded || Promise.resolve())
|
||||
.then(
|
||||
() => {
|
||||
panelEl = createCustomPanelElement(config);
|
||||
|
||||
const forwardEvent = (ev) => {
|
||||
if (window.parent.customPanel) {
|
||||
fireEvent(window.parent.customPanel, ev.type, ev.detail);
|
||||
}
|
||||
};
|
||||
panelEl!.addEventListener("hass-toggle-menu", forwardEvent);
|
||||
window.addEventListener("location-changed", (ev: any) =>
|
||||
navigate(
|
||||
window.parent.customPanel,
|
||||
window.location.pathname,
|
||||
ev.detail ? ev.detail.replace : false
|
||||
)
|
||||
);
|
||||
setProperties({ panel, ...properties });
|
||||
document.body.appendChild(panelEl!);
|
||||
},
|
||||
(err) => {
|
||||
// tslint:disable-next-line
|
||||
console.error(err, panel);
|
||||
alert(`Unable to load the panel source: ${err}.`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
() => window.parent.customPanel!.registerIframe(initialize, setProperties),
|
||||
{ once: true }
|
||||
);
|
@ -73,9 +73,9 @@ class HaPanelConfig extends HassRouterPage {
|
||||
import(/* webpackChunkName: "panel-config-users" */ "./users/ha-config-users"),
|
||||
},
|
||||
zha: {
|
||||
tag: "ha-config-zha",
|
||||
tag: "zha-config-panel",
|
||||
load: () =>
|
||||
import(/* webpackChunkName: "panel-config-zha" */ "./zha/ha-config-zha"),
|
||||
import(/* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-panel"),
|
||||
},
|
||||
zwave: {
|
||||
tag: "ha-config-zwave",
|
||||
|
@ -180,9 +180,9 @@ class HaConfigPerson extends LitElement {
|
||||
},
|
||||
removeEntry: async () => {
|
||||
if (
|
||||
!confirm(`Are you sure you want to delete this area?
|
||||
!confirm(`Are you sure you want to delete this person?
|
||||
|
||||
All devices in this area will become unassigned.`)
|
||||
All devices belonging to this person will become unassigned.`)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1,26 +1,26 @@
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "../../../components/ha-paper-icon-button-arrow-prev";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import "./zha-binding";
|
||||
import "./zha-cluster-attributes";
|
||||
import "./zha-cluster-commands";
|
||||
import "./zha-network";
|
||||
import "./zha-node";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import {
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { Cluster, ZHADevice, fetchBindableDevices } from "../../../data/zha";
|
||||
import "../../../layouts/ha-app-layout";
|
||||
import "../../../components/ha-paper-icon-button-arrow-prev";
|
||||
import { Cluster, fetchBindableDevices, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ZHAClusterSelectedParams, ZHADeviceSelectedParams } from "./types";
|
||||
import "./zha-cluster-attributes";
|
||||
import "./zha-cluster-commands";
|
||||
import "./zha-network";
|
||||
import "./zha-node";
|
||||
import "./zha-binding";
|
||||
|
||||
export class HaConfigZha extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@ -38,16 +38,7 @@ export class HaConfigZha extends LitElement {
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<ha-app-layout>
|
||||
<app-header slot="header">
|
||||
<app-toolbar>
|
||||
<ha-paper-icon-button-arrow-prev
|
||||
@click="${this._onBackTapped}"
|
||||
></ha-paper-icon-button-arrow-prev>
|
||||
<div main-title>Zigbee Home Automation</div>
|
||||
</app-toolbar>
|
||||
</app-header>
|
||||
|
||||
<hass-subpage header="Zigbee Home Automation">
|
||||
<zha-network
|
||||
.isWide="${this.isWide}"
|
||||
.hass="${this.hass}"
|
||||
@ -86,7 +77,7 @@ export class HaConfigZha extends LitElement {
|
||||
></zha-binding-control>
|
||||
`
|
||||
: ""}
|
||||
</ha-app-layout>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -117,10 +108,6 @@ export class HaConfigZha extends LitElement {
|
||||
static get styles(): CSSResult[] {
|
||||
return [haStyle];
|
||||
}
|
||||
|
||||
private _onBackTapped(): void {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -8,6 +8,12 @@ export interface ItemSelectedEvent {
|
||||
target?: PickerTarget;
|
||||
}
|
||||
|
||||
export interface ZHADeviceRemovedEvent {
|
||||
detail?: {
|
||||
device?: ZHADevice;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ChangeEvent {
|
||||
detail?: {
|
||||
value?: any;
|
||||
@ -22,7 +28,7 @@ export interface SetAttributeServiceData {
|
||||
cluster_type: string;
|
||||
attribute: number;
|
||||
value: any;
|
||||
manufacturer: number;
|
||||
manufacturer?: number;
|
||||
}
|
||||
|
||||
export interface IssueCommandServiceData {
|
||||
|
246
src/panels/config/zha/zha-add-devices-page.ts
Normal file
246
src/panels/config/zha/zha-add-devices-page.ts
Normal file
@ -0,0 +1,246 @@
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../components/ha-textarea";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import "./zha-device-card";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("zha-add-devices-page")
|
||||
class ZHAAddDevicesPage extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public isWide?: boolean;
|
||||
@property() private _error?: string;
|
||||
@property() private _discoveredDevices: ZHADevice[] = [];
|
||||
@property() private _formattedEvents: string = "";
|
||||
@property() private _active: boolean = false;
|
||||
@property() private _showHelp: boolean = false;
|
||||
private _addDevicesTimeoutHandle: any = undefined;
|
||||
private _subscribed?: Promise<() => Promise<void>>;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._subscribe();
|
||||
}
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._unsubscribe();
|
||||
this._error = undefined;
|
||||
this._discoveredDevices = [];
|
||||
this._formattedEvents = "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<hass-subpage
|
||||
header="${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.header"
|
||||
)}"
|
||||
>
|
||||
${this._active
|
||||
? html`
|
||||
<h2>
|
||||
<paper-spinner
|
||||
?active="${this._active}"
|
||||
alt="Searching"
|
||||
></paper-spinner>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.spinner"
|
||||
)}
|
||||
</h2>
|
||||
`
|
||||
: html`
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._subscribe} class="search-button">
|
||||
Search again
|
||||
</mwc-button>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
></paper-icon-button>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="permit"
|
||||
class="help-text"
|
||||
/>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`}
|
||||
${this._error
|
||||
? html`
|
||||
<div class="error">${this._error}</div>
|
||||
`
|
||||
: ""}
|
||||
<div class="content-header"></div>
|
||||
<div class="content">
|
||||
${this._discoveredDevices.length < 1
|
||||
? html`
|
||||
<div class="discovery-text">
|
||||
<h4>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.add_device_page.discovery_text"
|
||||
)}
|
||||
</h4>
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
${this._discoveredDevices.map(
|
||||
(device) => html`
|
||||
<zha-device-card
|
||||
class="card"
|
||||
.hass="${this.hass}"
|
||||
.device="${device}"
|
||||
.narrow="${!this.isWide}"
|
||||
.showHelp="${this._showHelp}"
|
||||
.showActions="${!this._active}"
|
||||
.isJoinPage="${true}"
|
||||
></zha-device-card>
|
||||
`
|
||||
)}
|
||||
`}
|
||||
</div>
|
||||
<ha-textarea class="events" value="${this._formattedEvents}">
|
||||
</ha-textarea>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleMessage(message: any): void {
|
||||
if (message.type === "log_output") {
|
||||
this._formattedEvents += message.log_entry.message + "\n";
|
||||
if (this.shadowRoot) {
|
||||
const textArea = this.shadowRoot.querySelector("ha-textarea");
|
||||
if (textArea) {
|
||||
textArea.scrollTop = textArea.scrollHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (message.type && message.type === "device_fully_initialized") {
|
||||
this._discoveredDevices.push(message.device_info);
|
||||
}
|
||||
}
|
||||
|
||||
private _unsubscribe(): void {
|
||||
this._active = false;
|
||||
if (this._addDevicesTimeoutHandle) {
|
||||
clearTimeout(this._addDevicesTimeoutHandle);
|
||||
}
|
||||
if (this._subscribed) {
|
||||
this._subscribed.then((unsub) => unsub());
|
||||
this._subscribed = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _subscribe(): void {
|
||||
this._subscribed = this.hass!.connection.subscribeMessage(
|
||||
(message) => this._handleMessage(message),
|
||||
{ type: "zha/devices/permit" }
|
||||
);
|
||||
this._active = true;
|
||||
this._addDevicesTimeoutHandle = setTimeout(
|
||||
() => this._unsubscribe(),
|
||||
60000
|
||||
);
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.discovery-text,
|
||||
.content-header {
|
||||
margin: 16px;
|
||||
}
|
||||
.content {
|
||||
border-top: 1px solid var(--light-primary-color);
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: left;
|
||||
overflow: scroll;
|
||||
}
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
paper-spinner {
|
||||
display: none;
|
||||
margin-right: 20px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
paper-spinner[active] {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
.card {
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.events {
|
||||
margin: 16px;
|
||||
border-top: 1px solid var(--light-primary-color);
|
||||
padding-top: 16px;
|
||||
min-height: 200px;
|
||||
max-height: 200px;
|
||||
overflow: scroll;
|
||||
}
|
||||
.toggle-help-icon {
|
||||
position: absolute;
|
||||
margin-top: 16px;
|
||||
margin-right: 16px;
|
||||
top: -6px;
|
||||
right: 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
ha-service-description {
|
||||
margin-top: 16px;
|
||||
margin-left: 16px;
|
||||
display: block;
|
||||
color: grey;
|
||||
}
|
||||
.search-button {
|
||||
margin-top: 16px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-add-devices-page": ZHAAddDevicesPage;
|
||||
}
|
||||
}
|
@ -1,20 +1,26 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
customElement,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { ZHADevice, bindDevices, unbindDevices } from "../../../data/zha";
|
||||
|
||||
import { bindDevices, unbindDevices, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
||||
@customElement("zha-binding-control")
|
||||
|
@ -1,17 +1,24 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
|
||||
import {
|
||||
Attribute,
|
||||
Cluster,
|
||||
@ -22,13 +29,12 @@ import {
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import {
|
||||
ChangeEvent,
|
||||
ItemSelectedEvent,
|
||||
SetAttributeServiceData,
|
||||
} from "./types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
|
||||
export class ZHAClusterAttributes extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@ -115,7 +121,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
</div>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div style="color: grey; padding: 16px">
|
||||
<div class="help-text">
|
||||
Select an attribute to view or set its value
|
||||
</div>
|
||||
`
|
||||
@ -152,6 +158,13 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
<mwc-button @click="${this._onGetZigbeeAttributeClick}"
|
||||
>Get Zigbee Attribute</mwc-button
|
||||
>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text2">
|
||||
Get the value for the selected attribute
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
@ -165,6 +178,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="set_zigbee_cluster_attribute"
|
||||
class="help-text2"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""}
|
||||
@ -201,7 +215,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
attribute: this._attributes[this._selectedAttributeIndex].id,
|
||||
manufacturer: this._manufacturerCodeOverride
|
||||
? parseInt(this._manufacturerCodeOverride as string, 10)
|
||||
: this.selectedNode!.manufacturer_code,
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@ -220,7 +234,7 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
value: this._attributeValue,
|
||||
manufacturer: this._manufacturerCodeOverride
|
||||
? parseInt(this._manufacturerCodeOverride as string, 10)
|
||||
: this.selectedNode!.manufacturer_code,
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@ -312,6 +326,16 @@ export class ZHAClusterAttributes extends LitElement {
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.help-text2 {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -1,15 +1,23 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
|
||||
import {
|
||||
Cluster,
|
||||
Command,
|
||||
@ -18,13 +26,12 @@ import {
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import {
|
||||
ChangeEvent,
|
||||
IssueCommandServiceData,
|
||||
ItemSelectedEvent,
|
||||
} from "./types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
|
||||
export class ZHAClusterCommands extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@ -107,7 +114,7 @@ export class ZHAClusterCommands extends LitElement {
|
||||
</div>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">Select a command to interact with</div>
|
||||
<div class="help-text">Select a command to interact with</div>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedCommandIndex !== -1
|
||||
@ -135,6 +142,7 @@ export class ZHAClusterCommands extends LitElement {
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="issue_zigbee_cluster_command"
|
||||
class="help-text2"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""}
|
||||
@ -242,7 +250,14 @@ export class ZHAClusterCommands extends LitElement {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.helpText {
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.help-text2 {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
|
@ -1,22 +1,27 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { Cluster, fetchClustersForZhaNode, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -90,7 +95,7 @@ export class ZHAClusters extends LitElement {
|
||||
</div>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
<div class="help-text">
|
||||
Select cluster to view attributes and commands
|
||||
</div>
|
||||
`
|
||||
@ -143,9 +148,11 @@ export class ZHAClusters extends LitElement {
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.helpText {
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
70
src/panels/config/zha/zha-config-panel.ts
Normal file
70
src/panels/config/zha/zha-config-panel.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import "../../../layouts/hass-loading-screen";
|
||||
|
||||
import { customElement, property } from "lit-element";
|
||||
|
||||
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||
import {
|
||||
HassRouterPage,
|
||||
RouterOptions,
|
||||
} from "../../../layouts/hass-router-page";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("zha-config-panel")
|
||||
class ZHAConfigPanel extends HassRouterPage {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public _wideSidebar: boolean = false;
|
||||
@property() public _wide: boolean = false;
|
||||
|
||||
protected routerOptions: RouterOptions = {
|
||||
defaultPage: "configuration",
|
||||
cacheAll: true,
|
||||
preloadAll: true,
|
||||
routes: {
|
||||
configuration: {
|
||||
tag: "ha-config-zha",
|
||||
load: () =>
|
||||
import(/* webpackChunkName: "zha-configuration-page" */ "./ha-config-zha"),
|
||||
},
|
||||
add: {
|
||||
tag: "zha-add-devices-page",
|
||||
load: () =>
|
||||
import(/* webpackChunkName: "zha-add-devices-page" */ "./zha-add-devices-page"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
private _listeners: Array<() => void> = [];
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._listeners.push(
|
||||
listenMediaQuery("(min-width: 1040px)", (matches) => {
|
||||
this._wide = matches;
|
||||
})
|
||||
);
|
||||
this._listeners.push(
|
||||
listenMediaQuery("(min-width: 1296px)", (matches) => {
|
||||
this._wideSidebar = matches;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
while (this._listeners.length) {
|
||||
this._listeners.pop()!();
|
||||
}
|
||||
}
|
||||
|
||||
protected updatePageEl(el): void {
|
||||
el.route = this.routeTail;
|
||||
el.hass = this.hass;
|
||||
el.isWide = this.hass.dockedSidebar ? this._wideSidebar : this._wide;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-config-panel": ZHAConfigPanel;
|
||||
}
|
||||
}
|
@ -1,40 +1,123 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/entity/state-badge";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import compare from "../../../common/string/compare";
|
||||
import {
|
||||
AreaRegistryEntry,
|
||||
fetchAreaRegistry,
|
||||
} from "../../../data/area_registry";
|
||||
import {
|
||||
DeviceRegistryEntryMutableParams,
|
||||
updateDeviceRegistryEntry,
|
||||
} from "../../../data/device_registry";
|
||||
import { reconfigureNode, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ItemSelectedEvent, NodeServiceData } from "./types";
|
||||
|
||||
import "../../../components/entity/state-badge";
|
||||
import { ZHADevice } from "../../../data/zha";
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"zha-device-removed": {
|
||||
device?: ZHADevice;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("zha-device-card")
|
||||
class ZHADeviceCard extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() public narrow?: boolean;
|
||||
@property() public device?: ZHADevice;
|
||||
@property() public showHelp: boolean = false;
|
||||
@property() public showActions?: boolean;
|
||||
@property() public isJoinPage?: boolean;
|
||||
@property() private _serviceData?: NodeServiceData;
|
||||
@property() private _areas: AreaRegistryEntry[] = [];
|
||||
@property() private _selectedAreaIndex: number = -1;
|
||||
|
||||
public firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener("hass-service-called", (ev) =>
|
||||
this.serviceCalled(ev)
|
||||
);
|
||||
this._serviceData = {
|
||||
ieee_address: this.device!.ieee,
|
||||
};
|
||||
fetchAreaRegistry(this.hass!).then((areas) => {
|
||||
this._areas = areas.sort((a, b) => compare(a.name, b.name));
|
||||
});
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("device")) {
|
||||
this._selectedAreaIndex =
|
||||
this._areas.findIndex((area) => area.area_id === this.device!.area_id) +
|
||||
1;
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected serviceCalled(ev): void {
|
||||
// Check if this is for us
|
||||
if (ev.detail.success && ev.detail.service === "remove") {
|
||||
fireEvent(this, "zha-device-removed", {
|
||||
device: this.device,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<paper-card>
|
||||
<paper-card heading="${this.isJoinPage ? this.device!.name : ""}">
|
||||
${
|
||||
this.isJoinPage
|
||||
? html`
|
||||
<div class="info">
|
||||
<div class="model">${this.device!.model}</div>
|
||||
<div class="manuf">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.integrations.config_entry.manuf",
|
||||
"manufacturer",
|
||||
this.device!.manufacturer
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
<div class="card-content">
|
||||
<dl>
|
||||
<dt class="label">IEEE:</dt>
|
||||
<dd class="info">${this.device!.ieee}</dd>
|
||||
<dt class="label">Quirk applied:</dt>
|
||||
<dd class="info">${this.device!.quirk_applied}</dd>
|
||||
<dt class="label">Quirk:</dt>
|
||||
<dd class="info">${this.device!.quirk_class}</dd>
|
||||
<dt>IEEE:</dt>
|
||||
<dd class="zha-info">${this.device!.ieee}</dd>
|
||||
${
|
||||
this.device!.quirk_applied
|
||||
? html`
|
||||
<dt>Quirk:</dt>
|
||||
<dd class="zha-info">${this.device!.quirk_class}</dd>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
@ -49,24 +132,145 @@ class ZHADeviceCard extends LitElement {
|
||||
.stateObj="${this.hass!.states[entity.entity_id]}"
|
||||
slot="item-icon"
|
||||
></state-badge>
|
||||
<paper-item-body>
|
||||
<div class="name">${entity.name}</div>
|
||||
<div class="secondary entity-id">${entity.entity_id}</div>
|
||||
</paper-item-body>
|
||||
${!this.isJoinPage
|
||||
? html`
|
||||
<paper-item-body>
|
||||
<div class="name">${entity.name}</div>
|
||||
<div class="secondary entity-id">
|
||||
${entity.entity_id}
|
||||
</div>
|
||||
</paper-item-body>
|
||||
`
|
||||
: ""}
|
||||
</paper-icon-item>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
<div class="editable">
|
||||
<paper-input
|
||||
type="string"
|
||||
@change="${this._saveCustomName}"
|
||||
placeholder="${this.hass!.localize(
|
||||
"ui.panel.config.zha.device_card.device_name_placeholder"
|
||||
)}"
|
||||
></paper-input>
|
||||
</div>
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu
|
||||
label="${this.hass!.localize(
|
||||
"ui.panel.config.zha.device_card.area_picker_label"
|
||||
)}"
|
||||
class="flex"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected="${this._selectedAreaIndex}"
|
||||
@iron-select="${this._selectedAreaChanged}"
|
||||
>
|
||||
<paper-item>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.integrations.config_entry.no_area"
|
||||
)}
|
||||
</paper-item>
|
||||
|
||||
${this._areas.map(
|
||||
(entry) => html`
|
||||
<paper-item area="${entry}">${entry.name}</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
${
|
||||
this.showActions
|
||||
? html`
|
||||
<div class="card-actions">
|
||||
<mwc-button @click="${this._onReconfigureNodeClick}"
|
||||
>Reconfigure Device</mwc-button
|
||||
>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.reconfigure"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
.serviceData="${this._serviceData}"
|
||||
>Remove Device</ha-call-service-button
|
||||
>
|
||||
${this.showHelp
|
||||
? html`
|
||||
<div class="help-text">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.remove"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
</paper-card>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _onReconfigureNodeClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
await reconfigureNode(this.hass, this.device!.ieee);
|
||||
}
|
||||
}
|
||||
|
||||
private async _saveCustomName(event): Promise<void> {
|
||||
if (this.hass) {
|
||||
const values: DeviceRegistryEntryMutableParams = {
|
||||
name_by_user: event.target.value,
|
||||
area_id: this.device!.area_id ? this.device!.area_id : undefined,
|
||||
};
|
||||
|
||||
await updateDeviceRegistryEntry(
|
||||
this.hass,
|
||||
this.device!.device_reg_id,
|
||||
values
|
||||
);
|
||||
|
||||
this.device!.user_given_name = event.target.value;
|
||||
}
|
||||
}
|
||||
|
||||
private _openMoreInfo(ev: MouseEvent): void {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: (ev.currentTarget as any).entity.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private async _selectedAreaChanged(event: ItemSelectedEvent) {
|
||||
if (!this.device || !this._areas) {
|
||||
return;
|
||||
}
|
||||
this._selectedAreaIndex = event!.target!.selected;
|
||||
const area = this._areas[this._selectedAreaIndex - 1]; // account for No Area
|
||||
if (
|
||||
(!area && !this.device.area_id) ||
|
||||
(area && area.area_id === this.device.area_id)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await updateDeviceRegistryEntry(this.hass!, this.device.device_reg_id, {
|
||||
area_id: area ? area.area_id : undefined,
|
||||
name_by_user: this.device!.user_given_name,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
@ -74,29 +278,43 @@ class ZHADeviceCard extends LitElement {
|
||||
:host(:not([narrow])) .device-entities {
|
||||
max-height: 225px;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: left;
|
||||
}
|
||||
paper-card {
|
||||
flex: 1 0 100%;
|
||||
padding-bottom: 10px;
|
||||
min-width: 0;
|
||||
min-width: 425px;
|
||||
}
|
||||
.device {
|
||||
width: 30%;
|
||||
}
|
||||
.label {
|
||||
.device .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
.device .manuf {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.extra-info {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.manuf,
|
||||
.zha-info,
|
||||
.entity-id {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.info {
|
||||
color: var(--secondary-text-color);
|
||||
font-weight: bold;
|
||||
margin-left: 16px;
|
||||
}
|
||||
dl dt {
|
||||
padding-left: 12px;
|
||||
float: left;
|
||||
width: 100px;
|
||||
width: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
dt dd {
|
||||
margin-left: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
paper-icon-item {
|
||||
@ -104,6 +322,36 @@ class ZHADeviceCard extends LitElement {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.editable {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
.flex {
|
||||
-ms-flex: 1 1 0.000000001px;
|
||||
-webkit-flex: 1;
|
||||
flex: 1;
|
||||
-webkit-flex-basis: 0.000000001px;
|
||||
flex-basis: 0.000000001px;
|
||||
}
|
||||
.node-picker {
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-ms-flex-direction: row;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
@ -114,5 +362,3 @@ declare global {
|
||||
"zha-device-card": ZHADeviceCard;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-device-card", ZHADeviceCard);
|
||||
|
@ -1,19 +1,22 @@
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
|
||||
export class ZHANetwork extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@ -30,6 +33,7 @@ export class ZHANetwork extends LitElement {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
_showHelp: {},
|
||||
_joinParams: {},
|
||||
};
|
||||
}
|
||||
|
||||
@ -37,29 +41,31 @@ export class ZHANetwork extends LitElement {
|
||||
return html`
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div style="position: relative" slot="header">
|
||||
<span>Network Management</span>
|
||||
<paper-icon-button class="toggle-help-icon" @click="${
|
||||
this._onHelpTap
|
||||
}" icon="hass:help-circle"></paper-icon-button>
|
||||
<span>Network Management</span>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">Commands that affect entire network</span>
|
||||
|
||||
<paper-card class="content">
|
||||
<div class="card-actions">
|
||||
<ha-call-service-button .hass="${
|
||||
this.hass
|
||||
}" domain="zha" service="permit">Permit</ha-call-service-button>
|
||||
${
|
||||
this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="permit"
|
||||
/>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._onAddDevicesClick}>
|
||||
Add Devices
|
||||
</mwc-button>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="permit"
|
||||
class="help-text2"
|
||||
/>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</paper-card>
|
||||
</ha-config-section>
|
||||
`;
|
||||
@ -69,6 +75,10 @@ export class ZHANetwork extends LitElement {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private _onAddDevicesClick() {
|
||||
navigate(this, "add");
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
@ -102,6 +112,11 @@ export class ZHANetwork extends LitElement {
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.help-text2 {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
PropertyValues,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
import "./zha-clusters";
|
||||
import "./zha-device-card";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { fetchDevices, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent, NodeServiceData, ChangeEvent } from "./types";
|
||||
import "./zha-clusters";
|
||||
import "./zha-device-card";
|
||||
import {
|
||||
updateDeviceRegistryEntry,
|
||||
DeviceRegistryEntryMutableParams,
|
||||
} from "../../../data/device_registry";
|
||||
import { reconfigureNode, fetchDevices, ZHADevice } from "../../../data/zha";
|
||||
import { ItemSelectedEvent, ZHADeviceRemovedEvent } from "./types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -37,60 +35,25 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("zha-node")
|
||||
export class ZHANode extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
private _showHelp: boolean;
|
||||
private _selectedNodeIndex: number;
|
||||
private _selectedNode?: ZHADevice;
|
||||
private _serviceData?: {};
|
||||
private _nodes: ZHADevice[];
|
||||
private _userSelectedName?: string;
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() public isWide?: boolean;
|
||||
@property() private _showHelp: boolean = false;
|
||||
@property() private _selectedDeviceIndex: number = -1;
|
||||
@property() private _selectedDevice?: ZHADevice;
|
||||
@property() private _nodes: ZHADevice[] = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._showHelp = false;
|
||||
this._selectedNodeIndex = -1;
|
||||
this._nodes = [];
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
_showHelp: {},
|
||||
_selectedNodeIndex: {},
|
||||
_selectedNode: {},
|
||||
_entities: {},
|
||||
_serviceData: {},
|
||||
_nodes: {},
|
||||
_userSelectedName: {},
|
||||
};
|
||||
}
|
||||
|
||||
public firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
if (this._nodes.length === 0) {
|
||||
this._fetchDevices();
|
||||
}
|
||||
this.addEventListener("hass-service-called", (ev) =>
|
||||
this.serviceCalled(ev)
|
||||
);
|
||||
}
|
||||
|
||||
protected serviceCalled(ev): void {
|
||||
// Check if this is for us
|
||||
if (ev.detail.success && ev.detail.service === "remove") {
|
||||
this._selectedNodeIndex = -1;
|
||||
this._fetchDevices();
|
||||
}
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._fetchDevices();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div class="sectionHeader" slot="header">
|
||||
<span>Node Management</span>
|
||||
<span>Device Management</span>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
@ -98,8 +61,8 @@ export class ZHANode extends LitElement {
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">
|
||||
Run ZHA commands that affect a single node. Pick a node to see a list
|
||||
of available commands. <br /><br />Note: Sleepy (battery powered)
|
||||
Run ZHA commands that affect a single device. Pick a device to see a
|
||||
list of available commands. <br /><br />Note: Sleepy (battery powered)
|
||||
devices need to be awake when executing commands against them. You can
|
||||
generally wake a sleepy device by triggering it. <br /><br />Some
|
||||
devices such as Xiaomi sensors have a wake up button that you can
|
||||
@ -108,11 +71,15 @@ export class ZHANode extends LitElement {
|
||||
</span>
|
||||
<paper-card class="content">
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu label="Nodes" class="flex">
|
||||
<paper-dropdown-menu
|
||||
label="Devices"
|
||||
class="flex"
|
||||
id="zha-device-selector"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
@iron-select="${this._selectedNodeChanged}"
|
||||
.selected="${this._selectedNodeIndex}"
|
||||
@iron-select="${this._selectedDeviceChanged}"
|
||||
.selected="${this._selectedDeviceIndex}"
|
||||
>
|
||||
${this._nodes.map(
|
||||
(entry) => html`
|
||||
@ -128,95 +95,36 @@ export class ZHANode extends LitElement {
|
||||
</div>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
Select node to view per-node options
|
||||
<div class="help-text">
|
||||
Select device to view per-device options
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedNodeIndex !== -1
|
||||
${this._selectedDeviceIndex !== -1
|
||||
? html`
|
||||
<zha-device-card
|
||||
class="card"
|
||||
.hass="${this.hass}"
|
||||
.device="${this._selectedNode}"
|
||||
.device="${this._selectedDevice}"
|
||||
.narrow="${!this.isWide}"
|
||||
.showHelp="${this._showHelp}"
|
||||
.showActions="${true}"
|
||||
@zha-device-removed="${this._onDeviceRemoved}"
|
||||
.isJoinPage="${false}"
|
||||
></zha-device-card>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedNodeIndex !== -1
|
||||
? html`
|
||||
<div class="input-text">
|
||||
<paper-input
|
||||
type="string"
|
||||
.value="${this._userSelectedName}"
|
||||
@value-changed="${this._onUserSelectedNameChanged}"
|
||||
placeholder="User given name"
|
||||
></paper-input>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${this._selectedNodeIndex !== -1 ? this._renderNodeActions() : ""}
|
||||
${this._selectedNode ? this._renderClusters() : ""}
|
||||
${this._selectedDevice ? this._renderClusters() : ""}
|
||||
</paper-card>
|
||||
</ha-config-section>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderNodeActions(): TemplateResult {
|
||||
return html`
|
||||
<div class="card-actions">
|
||||
<mwc-button @click="${this._onReconfigureNodeClick}"
|
||||
>Reconfigure Node</mwc-button
|
||||
>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.reconfigure"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
.serviceData="${this._serviceData}"
|
||||
>Remove Node</ha-call-service-button
|
||||
>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
/>
|
||||
`
|
||||
: ""}
|
||||
<mwc-button
|
||||
@click="${this._onUpdateDeviceNameClick}"
|
||||
.disabled="${!this._userSelectedName ||
|
||||
this._userSelectedName === ""}"
|
||||
>Update Name</mwc-button
|
||||
>
|
||||
${this._showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.zha.services.updateDeviceName"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderClusters(): TemplateResult {
|
||||
return html`
|
||||
<zha-clusters
|
||||
.hass="${this.hass}"
|
||||
.selectedDevice="${this._selectedNode}"
|
||||
.selectedDevice="${this._selectedDevice}"
|
||||
.showHelp="${this._showHelp}"
|
||||
></zha-clusters>
|
||||
`;
|
||||
@ -226,45 +134,10 @@ export class ZHANode extends LitElement {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private _selectedNodeChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedNodeIndex = event!.target!.selected;
|
||||
this._selectedNode = this._nodes[this._selectedNodeIndex];
|
||||
this._userSelectedName = "";
|
||||
fireEvent(this, "zha-node-selected", { node: this._selectedNode });
|
||||
this._serviceData = this._computeNodeServiceData();
|
||||
}
|
||||
|
||||
private async _onReconfigureNodeClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
await reconfigureNode(this.hass, this._selectedNode!.ieee);
|
||||
}
|
||||
}
|
||||
|
||||
private _onUserSelectedNameChanged(value: ChangeEvent): void {
|
||||
this._userSelectedName = value.detail!.value;
|
||||
}
|
||||
|
||||
private async _onUpdateDeviceNameClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
const values: DeviceRegistryEntryMutableParams = {
|
||||
name_by_user: this._userSelectedName,
|
||||
};
|
||||
|
||||
await updateDeviceRegistryEntry(
|
||||
this.hass,
|
||||
this._selectedNode!.device_reg_id,
|
||||
values
|
||||
);
|
||||
|
||||
this._selectedNode!.user_given_name = this._userSelectedName!;
|
||||
this._userSelectedName = "";
|
||||
}
|
||||
}
|
||||
|
||||
private _computeNodeServiceData(): NodeServiceData {
|
||||
return {
|
||||
ieee_address: this._selectedNode!.ieee,
|
||||
};
|
||||
private _selectedDeviceChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedDeviceIndex = event!.target!.selected;
|
||||
this._selectedDevice = this._nodes[this._selectedDeviceIndex];
|
||||
fireEvent(this, "zha-node-selected", { node: this._selectedDevice });
|
||||
}
|
||||
|
||||
private async _fetchDevices() {
|
||||
@ -273,6 +146,13 @@ export class ZHANode extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _onDeviceRemoved(event: ZHADeviceRemovedEvent): void {
|
||||
this._selectedDeviceIndex = -1;
|
||||
this._nodes.splice(this._nodes.indexOf(event.detail!.device!), 1);
|
||||
this._selectedDevice = undefined;
|
||||
fireEvent(this, "zha-node-selected", { node: this._selectedDevice });
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
@ -298,13 +178,10 @@ export class ZHANode extends LitElement {
|
||||
}
|
||||
|
||||
.help-text {
|
||||
color: grey;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
}
|
||||
|
||||
.helpText {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
paper-card {
|
||||
@ -355,12 +232,6 @@ export class ZHANode extends LitElement {
|
||||
right: 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.input-text {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
@ -371,5 +242,3 @@ declare global {
|
||||
"zha-node": ZHANode;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-node", ZHANode);
|
||||
|
@ -1,50 +1,69 @@
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { property, PropertyValues, UpdatingElement } from "lit-element";
|
||||
import { loadCustomPanel } from "../../util/custom-panel/load-custom-panel";
|
||||
import { createCustomPanelElement } from "../../util/custom-panel/create-custom-panel-element";
|
||||
import { setCustomPanelProperties } from "../../util/custom-panel/set-custom-panel-properties";
|
||||
import { HomeAssistant, Route, Panel } from "../../types";
|
||||
import { CustomPanelConfig } from "../../data/panel_custom";
|
||||
|
||||
import EventsMixin from "../../mixins/events-mixin";
|
||||
import NavigateMixin from "../../mixins/navigate-mixin";
|
||||
import loadCustomPanel from "../../util/custom-panel/load-custom-panel";
|
||||
import createCustomPanelElement from "../../util/custom-panel/create-custom-panel-element";
|
||||
import setCustomPanelProperties from "../../util/custom-panel/set-custom-panel-properties";
|
||||
declare global {
|
||||
interface Window {
|
||||
customPanel: HaPanelCustom | undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mixins are used by ifram to communicate with main frontend.
|
||||
* @appliesMixin EventsMixin
|
||||
* @appliesMixin NavigateMixin
|
||||
*/
|
||||
class HaPanelCustom extends NavigateMixin(EventsMixin(PolymerElement)) {
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
narrow: Boolean,
|
||||
route: Object,
|
||||
panel: {
|
||||
type: Object,
|
||||
observer: "_panelChanged",
|
||||
},
|
||||
};
|
||||
export class HaPanelCustom extends UpdatingElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public narrow!: boolean;
|
||||
@property() public route!: Route;
|
||||
@property() public panel!: Panel;
|
||||
private _setProperties?: (props: {}) => void | undefined;
|
||||
|
||||
public registerIframe(initialize, setProperties) {
|
||||
initialize(this.panel, {
|
||||
hass: this.hass,
|
||||
narrow: this.narrow,
|
||||
route: this.route,
|
||||
});
|
||||
this._setProperties = setProperties;
|
||||
}
|
||||
|
||||
static get observers() {
|
||||
return ["_dataChanged(hass, narrow, route)"];
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._cleanupPanel();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._setProperties = null;
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
if (changedProps.has("panel")) {
|
||||
// Clean up old things if we had a panel
|
||||
if (changedProps.get("panel")) {
|
||||
this._cleanupPanel();
|
||||
}
|
||||
this._createPanel(this.panel);
|
||||
return;
|
||||
}
|
||||
if (!this._setProperties) {
|
||||
return;
|
||||
}
|
||||
const props = {};
|
||||
for (const key of changedProps.keys()) {
|
||||
props[key] = this[key];
|
||||
}
|
||||
this._setProperties(props);
|
||||
}
|
||||
|
||||
_panelChanged(panel) {
|
||||
// Clean up
|
||||
private _cleanupPanel() {
|
||||
delete window.customPanel;
|
||||
this._setProperties = null;
|
||||
this._setProperties = undefined;
|
||||
while (this.lastChild) {
|
||||
this.removeChild(this.lastChild);
|
||||
}
|
||||
}
|
||||
|
||||
const config = panel.config._panel_custom;
|
||||
private _createPanel(panel: Panel) {
|
||||
const config = panel.config!._panel_custom as CustomPanelConfig;
|
||||
|
||||
const tempA = document.createElement("a");
|
||||
tempA.href = config.html_url || config.js_url || config.module_url;
|
||||
tempA.href = config.html_url || config.js_url || config.module_url || "";
|
||||
|
||||
if (
|
||||
!config.trust_external &&
|
||||
@ -96,32 +115,13 @@ It will have access to all data in Home Assistant.
|
||||
</style>
|
||||
<iframe></iframe>
|
||||
`.trim();
|
||||
const iframeDoc = this.querySelector("iframe").contentWindow.document;
|
||||
const iframeDoc = this.querySelector("iframe")!.contentWindow!.document;
|
||||
iframeDoc.open();
|
||||
iframeDoc.write(
|
||||
`<!doctype html><script src='${window.customPanelJS}'></script>`
|
||||
);
|
||||
iframeDoc.close();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
delete window.customPanel;
|
||||
}
|
||||
|
||||
_dataChanged(hass, narrow, route) {
|
||||
if (!this._setProperties) return;
|
||||
this._setProperties({ hass, narrow, route });
|
||||
}
|
||||
|
||||
registerIframe(initialize, setProperties) {
|
||||
initialize(this.panel, {
|
||||
hass: this.hass,
|
||||
narrow: this.narrow,
|
||||
route: this.route,
|
||||
});
|
||||
this._setProperties = setProperties;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-panel-custom", HaPanelCustom);
|
@ -10,17 +10,17 @@ import {
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-label-badge";
|
||||
import "../components/hui-warning";
|
||||
|
||||
import { LovelaceCard } from "../types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import {
|
||||
callAlarmAction,
|
||||
FORMAT_NUMBER,
|
||||
} from "../../../data/alarm_control_panel";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-label-badge";
|
||||
import "../components/hui-warning";
|
||||
import { AlarmPanelCardConfig } from "./types";
|
||||
|
||||
const ICONS = {
|
||||
armed_away: "hass:shield-lock",
|
||||
@ -34,12 +34,6 @@ const ICONS = {
|
||||
|
||||
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"];
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
states?: string[];
|
||||
}
|
||||
|
||||
@customElement("hui-alarm-panel-card")
|
||||
class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement() {
|
||||
@ -53,7 +47,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: AlarmPanelCardConfig;
|
||||
|
||||
@property() private _code?: string;
|
||||
|
||||
@ -69,7 +63,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
: 8;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: AlarmPanelCardConfig): void {
|
||||
if (
|
||||
!config ||
|
||||
!config.entity ||
|
||||
@ -305,7 +299,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
|
||||
.actions mwc-button {
|
||||
min-width: calc(var(--base-unit) * 9);
|
||||
margin: 0 4px;
|
||||
margin: 0 4px 4px;
|
||||
}
|
||||
|
||||
mwc-button#disarm {
|
||||
|
@ -1,22 +1,16 @@
|
||||
import { createCardElement } from "../common/create-card-element";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import {
|
||||
Condition,
|
||||
checkConditionsMet,
|
||||
validateConditionalConfig,
|
||||
} from "../../lovelace/common/validate-condition";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
|
||||
interface Config extends LovelaceCardConfig {
|
||||
card: LovelaceCardConfig;
|
||||
conditions: Condition[];
|
||||
}
|
||||
import { ConditionalCardConfig } from "./types";
|
||||
|
||||
class HuiConditionalCard extends HTMLElement implements LovelaceCard {
|
||||
private _hass?: HomeAssistant;
|
||||
private _config?: Config;
|
||||
private _config?: ConditionalCardConfig;
|
||||
private _card?: LovelaceCard;
|
||||
|
||||
public setConfig(config) {
|
||||
|
@ -11,13 +11,8 @@ import {
|
||||
import "@polymer/paper-card/paper-card";
|
||||
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
content: string;
|
||||
title?: string;
|
||||
}
|
||||
import { EmptyStateCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-empty-state-card")
|
||||
export class HuiEmptyStateCard extends LitElement implements LovelaceCard {
|
||||
@ -27,7 +22,7 @@ export class HuiEmptyStateCard extends LitElement implements LovelaceCard {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public setConfig(_config: Config): void {
|
||||
public setConfig(_config: EmptyStateCardConfig): void {
|
||||
// tslint:disable-next-line
|
||||
}
|
||||
|
||||
|
@ -15,30 +15,15 @@ import "../components/hui-entities-toggle";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityConfig, EntityRow } from "../entity-rows/types";
|
||||
import { EntityRow } from "../entity-rows/types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import { createRowElement } from "../common/create-row-element";
|
||||
import { EntitiesCardConfig, EntitiesCardEntityConfig } from "./types";
|
||||
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
|
||||
export interface EntitiesCardEntityConfig extends EntityConfig {
|
||||
type?: string;
|
||||
secondary_info?: "entity-id" | "last-changed";
|
||||
action_name?: string;
|
||||
service?: string;
|
||||
service_data?: object;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface EntitiesCardConfig extends LovelaceCardConfig {
|
||||
show_header_toggle?: boolean;
|
||||
title?: string;
|
||||
entities: EntitiesCardEntityConfig[];
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
@customElement("hui-entities-card")
|
||||
class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
|
@ -21,21 +21,13 @@ import computeStateDomain from "../../../common/entity/compute_state_domain";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
|
||||
import { HomeAssistant, LightEntity } from "../../../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
icon?: string;
|
||||
theme?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
import { EntityButtonCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-entity-button-card")
|
||||
class HuiEntityButtonCard extends LitElement implements LovelaceCard {
|
||||
@ -48,18 +40,20 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard {
|
||||
return {
|
||||
tap_action: { action: "toggle" },
|
||||
hold_action: { action: "more-info" },
|
||||
show_icon: true,
|
||||
show_name: true,
|
||||
};
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: EntityButtonCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: EntityButtonCardConfig): void {
|
||||
if (!isValidEntityId(config.entity)) {
|
||||
throw new Error("Invalid Entity");
|
||||
}
|
||||
@ -67,6 +61,8 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard {
|
||||
this._config = {
|
||||
theme: "default",
|
||||
hold_action: { action: "more-info" },
|
||||
show_icon: true,
|
||||
show_name: true,
|
||||
...config,
|
||||
};
|
||||
|
||||
@ -126,18 +122,26 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard {
|
||||
@ha-hold="${this._handleHold}"
|
||||
.longPress="${longPress()}"
|
||||
>
|
||||
<ha-icon
|
||||
data-domain="${computeStateDomain(stateObj)}"
|
||||
data-state="${stateObj.state}"
|
||||
.icon="${this._config.icon || stateIcon(stateObj)}"
|
||||
style="${styleMap({
|
||||
filter: this._computeBrightness(stateObj),
|
||||
color: this._computeColor(stateObj),
|
||||
})}"
|
||||
></ha-icon>
|
||||
<span>
|
||||
${this._config.name || computeStateName(stateObj)}
|
||||
</span>
|
||||
${this._config.show_icon
|
||||
? html`
|
||||
<ha-icon
|
||||
data-domain="${computeStateDomain(stateObj)}"
|
||||
data-state="${stateObj.state}"
|
||||
.icon="${this._config.icon || stateIcon(stateObj)}"
|
||||
style="${styleMap({
|
||||
filter: this._computeBrightness(stateObj),
|
||||
color: this._computeColor(stateObj),
|
||||
})}"
|
||||
></ha-icon>
|
||||
`
|
||||
: ""}
|
||||
${this._config.show_name
|
||||
? html`
|
||||
<span>
|
||||
${this._config.name || computeStateName(stateObj)}
|
||||
</span>
|
||||
`
|
||||
: ""}
|
||||
<mwc-ripple></mwc-ripple>
|
||||
</ha-card>
|
||||
`;
|
||||
|
@ -4,14 +4,7 @@ import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
export interface EntityFilterCardConfig extends LovelaceCardConfig {
|
||||
type: "entity-filter";
|
||||
entities: Array<EntityConfig | string>;
|
||||
state_filter: string[];
|
||||
card: Partial<LovelaceCardConfig>;
|
||||
show_empty?: boolean;
|
||||
}
|
||||
import { EntityFilterCardConfig } from "./types";
|
||||
|
||||
class EntityFilterCard extends HTMLElement implements LovelaceCard {
|
||||
public isPanel?: boolean;
|
||||
|
@ -11,11 +11,7 @@ import {
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
interface Config extends LovelaceCardConfig {
|
||||
error: string;
|
||||
origConfig: LovelaceCardConfig;
|
||||
}
|
||||
import { ErrorCardConfig } from "./types";
|
||||
|
||||
export const createErrorCardElement = (config) => {
|
||||
const el = document.createElement("hui-error-card");
|
||||
@ -33,13 +29,13 @@ export const createErrorCardConfig = (error, origConfig) => ({
|
||||
export class HuiErrorCard extends LitElement implements LovelaceCard {
|
||||
public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: ErrorCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ErrorCardConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
|
@ -13,31 +13,15 @@ import { styleMap } from "lit-html/directives/style-map";
|
||||
import "../../../components/ha-card";
|
||||
import "../components/hui-warning";
|
||||
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
|
||||
import isValidEntityId from "../../../common/entity/valid_entity_id";
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
export interface SeverityConfig {
|
||||
green?: number;
|
||||
yellow?: number;
|
||||
red?: number;
|
||||
}
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
unit?: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
severity?: SeverityConfig;
|
||||
theme?: string;
|
||||
}
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { GaugeCardConfig } from "./types";
|
||||
|
||||
export const severityMap = {
|
||||
red: "var(--label-badge-red)",
|
||||
@ -58,7 +42,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: GaugeCardConfig;
|
||||
|
||||
private _updated?: boolean;
|
||||
|
||||
@ -66,7 +50,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: GaugeCardConfig): void {
|
||||
if (!config || !config.entity) {
|
||||
throw new Error("Invalid card configuration");
|
||||
}
|
||||
|
@ -10,14 +10,6 @@ import {
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
|
||||
import computeStateDisplay from "../../../common/entity/compute_state_display";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
@ -25,22 +17,14 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
import "../../../components/entity/state-badge";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import "../components/hui-warning";
|
||||
import "../components/hui-warning-element";
|
||||
|
||||
export interface ConfigEntity extends EntityConfig {
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
||||
export interface GlanceCardConfig extends LovelaceCardConfig {
|
||||
show_name?: boolean;
|
||||
show_state?: boolean;
|
||||
show_icon?: boolean;
|
||||
title?: string;
|
||||
theme?: string;
|
||||
entities: ConfigEntity[];
|
||||
columns?: number;
|
||||
}
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { GlanceCardConfig, ConfigEntity } from "./types";
|
||||
|
||||
@customElement("hui-glance-card")
|
||||
export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
||||
@ -184,13 +168,13 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<hui-warning
|
||||
>${this.hass!.localize(
|
||||
<hui-warning-element
|
||||
label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.warning.entity_not_found",
|
||||
"entity",
|
||||
entityConf.entity
|
||||
)}</hui-warning
|
||||
>
|
||||
)}
|
||||
></hui-warning-element>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -11,14 +11,8 @@ import {
|
||||
import "../../../components/ha-card";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
aspect_ratio?: string;
|
||||
title?: string;
|
||||
url: string;
|
||||
}
|
||||
import { IframeCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-iframe-card")
|
||||
export class HuiIframeCard extends LitElement implements LovelaceCard {
|
||||
@ -30,7 +24,7 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
|
||||
return { url: "https://www.home-assistant.io", aspect_ratio: "50%" };
|
||||
}
|
||||
|
||||
@property() protected _config?: Config;
|
||||
@property() protected _config?: IframeCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
if (!this._config) {
|
||||
@ -42,7 +36,7 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
|
||||
return 1 + aspectRatio / 25;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: IframeCardConfig): void {
|
||||
if (!config.url) {
|
||||
throw new Error("URL required");
|
||||
}
|
||||
|
@ -8,15 +8,6 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
import { HomeAssistant, LightEntity } from "../../../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
||||
import { toggleEntity } from "../common/entity/toggle-entity";
|
||||
|
||||
import stateIcon from "../../../common/entity/state_icon";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
@ -25,6 +16,15 @@ import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import "../components/hui-warning";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
import { HomeAssistant, LightEntity } from "../../../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
||||
import { toggleEntity } from "../common/entity/toggle-entity";
|
||||
import { LightCardConfig } from "./types";
|
||||
|
||||
const lightConfig = {
|
||||
radius: 80,
|
||||
step: 1,
|
||||
@ -40,12 +40,6 @@ const lightConfig = {
|
||||
animation: false,
|
||||
};
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
@customElement("hui-light-card")
|
||||
export class HuiLightCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
@ -58,7 +52,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: LightCardConfig;
|
||||
|
||||
@property() private _roundSliderStyle?: TemplateResult;
|
||||
|
||||
@ -70,7 +64,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: LightCardConfig): void {
|
||||
if (!config.entity || config.entity.split(".")[0] !== "light") {
|
||||
throw new Error("Specify an entity from within the light domain.");
|
||||
}
|
||||
|
@ -21,20 +21,13 @@ import computeStateDomain from "../../../common/entity/compute_state_domain";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import debounce from "../../../common/util/debounce";
|
||||
import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
|
||||
export interface MapCardConfig extends LovelaceCardConfig {
|
||||
title: string;
|
||||
aspect_ratio: string;
|
||||
default_zoom?: number;
|
||||
entities?: Array<EntityConfig | string>;
|
||||
geo_location_sources?: string[];
|
||||
}
|
||||
import { MapCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-map-card")
|
||||
class HuiMapCard extends LitElement implements LovelaceCard {
|
||||
|
@ -13,12 +13,7 @@ import "../../../components/ha-card";
|
||||
import "../../../components/ha-markdown";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
content: string;
|
||||
title?: string;
|
||||
}
|
||||
import { MarkdownCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-markdown-card")
|
||||
export class HuiMarkdownCard extends LitElement implements LovelaceCard {
|
||||
@ -31,13 +26,13 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard {
|
||||
return { content: " " };
|
||||
}
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: MarkdownCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
return this._config!.content.split("\n").length;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: MarkdownCardConfig): void {
|
||||
if (!config.content) {
|
||||
throw new Error("Invalid Configuration: Content Required");
|
||||
}
|
||||
|
@ -2,11 +2,6 @@ import "../../../cards/ha-media_player-card";
|
||||
|
||||
import LegacyWrapperCard from "./hui-legacy-wrapper-card";
|
||||
|
||||
// should be interface when converted to TS
|
||||
export const Config = {
|
||||
entity: "",
|
||||
};
|
||||
|
||||
class HuiMediaControlCard extends LegacyWrapperCard {
|
||||
static async getConfigElement() {
|
||||
await import(/* webpackChunkName: "hui-media-control-card-editor" */ "../editor/config-elements/hui-media-control-card-editor");
|
||||
|
@ -11,17 +11,11 @@ import {
|
||||
import "../../../components/ha-card";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
image?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
import { PictureCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-picture-card")
|
||||
export class HuiPictureCard extends LitElement implements LovelaceCard {
|
||||
@ -40,13 +34,13 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
|
||||
|
||||
public hass?: HomeAssistant;
|
||||
|
||||
@property() protected _config?: Config;
|
||||
@property() protected _config?: PictureCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: PictureCardConfig): void {
|
||||
if (!config || !config.image) {
|
||||
throw new Error("Invalid Configuration: 'image' required");
|
||||
}
|
||||
|
@ -9,25 +9,14 @@ import {
|
||||
} from "lit-element";
|
||||
|
||||
import { createStyledHuiElement } from "./picture-elements/create-styled-hui-element";
|
||||
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceElementConfig, LovelaceElement } from "../elements/types";
|
||||
|
||||
interface Config extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
state_image?: {};
|
||||
aspect_ratio?: string;
|
||||
entity?: string;
|
||||
elements: LovelaceElementConfig[];
|
||||
}
|
||||
import { PictureElementsCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-picture-elements-card")
|
||||
class HuiPictureElementsCard extends LitElement implements LovelaceCard {
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: PictureElementsCardConfig;
|
||||
|
||||
private _hass?: HomeAssistant;
|
||||
|
||||
@ -43,7 +32,7 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: PictureElementsCardConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid Configuration");
|
||||
} else if (
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
property,
|
||||
css,
|
||||
CSSResult,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
@ -19,35 +20,23 @@ import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
|
||||
interface Config extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
state_image?: {};
|
||||
aspect_ratio?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
show_name?: boolean;
|
||||
show_state?: boolean;
|
||||
}
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { PictureEntityCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-picture-entity-card")
|
||||
class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: PictureEntityCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: PictureEntityCardConfig): void {
|
||||
if (!config || !config.entity) {
|
||||
throw new Error("Invalid Configuration: 'entity' required");
|
||||
}
|
||||
@ -62,6 +51,10 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
this._config = { show_name: true, show_state: true, ...config };
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
|
@ -6,16 +6,10 @@ import {
|
||||
property,
|
||||
css,
|
||||
CSSResult,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import computeStateDisplay from "../../../common/entity/compute_state_display";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
@ -24,29 +18,26 @@ import stateIcon from "../../../common/entity/state_icon";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import "../components/hui-image";
|
||||
import "../components/hui-warning-element";
|
||||
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { toggleEntity } from "../common/entity/toggle-entity";
|
||||
import { PictureGlanceCardConfig } from "./types";
|
||||
|
||||
const STATES_OFF = new Set(["closed", "locked", "not_home", "off"]);
|
||||
|
||||
interface Config extends LovelaceCardConfig {
|
||||
entities: EntityConfig[];
|
||||
title?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
state_image?: {};
|
||||
aspect_ratio?: string;
|
||||
entity?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
||||
@customElement("hui-picture-glance-card")
|
||||
class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: PictureGlanceCardConfig;
|
||||
|
||||
private _entitiesDialog?: EntityConfig[];
|
||||
|
||||
@ -56,7 +47,7 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: PictureGlanceCardConfig): void {
|
||||
if (
|
||||
!config ||
|
||||
!config.entities ||
|
||||
@ -85,6 +76,39 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
if (changedProps.has("_config")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this._entitiesDialog) {
|
||||
for (const entity of this._entitiesDialog) {
|
||||
if (
|
||||
oldHass.states[entity.entity] !== this.hass!.states[entity.entity]
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._entitiesToggle) {
|
||||
for (const entity of this._entitiesToggle) {
|
||||
if (
|
||||
oldHass.states[entity.entity] !== this.hass!.states[entity.entity]
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
@ -138,7 +162,15 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
const stateObj = this.hass!.states[entityConf.entity];
|
||||
|
||||
if (!stateObj) {
|
||||
return html``;
|
||||
return html`
|
||||
<hui-warning-element
|
||||
label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.warning.entity_not_found",
|
||||
"entity",
|
||||
entityConf.entity
|
||||
)}
|
||||
></hui-warning-element>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
|
@ -6,18 +6,20 @@ import {
|
||||
CSSResult,
|
||||
property,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
import { LovelaceCardEditor, LovelaceCard } from "../types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { PlantStatusCardConfig, PlantAttributeTarget } from "./types";
|
||||
|
||||
const SENSORS = {
|
||||
moisture: "hass:water",
|
||||
@ -27,15 +29,6 @@ const SENSORS = {
|
||||
battery: "hass:battery",
|
||||
};
|
||||
|
||||
export interface PlantAttributeTarget extends EventTarget {
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export interface PlantStatusConfig extends LovelaceCardConfig {
|
||||
name?: string;
|
||||
entity: string;
|
||||
}
|
||||
|
||||
@customElement("hui-plant-status-card")
|
||||
class HuiPlantStatusCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
@ -49,13 +42,13 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: PlantStatusConfig;
|
||||
@property() private _config?: PlantStatusCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public setConfig(config: PlantStatusConfig): void {
|
||||
public setConfig(config: PlantStatusCardConfig): void {
|
||||
if (!config.entity || config.entity.split(".")[0] !== "plant") {
|
||||
throw new Error("Specify an entity from within the plant domain.");
|
||||
}
|
||||
@ -63,6 +56,10 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
@ -91,7 +88,7 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
|
||||
style="background-image:url(${stateObj.attributes.entity_picture})"
|
||||
>
|
||||
<div class="header">
|
||||
${this._config.title || computeStateName(stateObj)}
|
||||
${this._config.name || computeStateName(stateObj)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
|
@ -11,12 +11,6 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { fetchRecent } from "../../../data/history";
|
||||
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import stateIcon from "../../../common/entity/state_icon";
|
||||
@ -25,6 +19,13 @@ import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import "../components/hui-warning";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { fetchRecent } from "../../../data/history";
|
||||
import { SensorCardConfig } from "./types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
const midPoint = (
|
||||
_Ax: number,
|
||||
_Ay: number,
|
||||
@ -137,17 +138,6 @@ const coordinates = (
|
||||
return calcPoints(history, hours, width, detail, min, max);
|
||||
};
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
icon?: string;
|
||||
graph?: string;
|
||||
unit?: string;
|
||||
detail?: number;
|
||||
theme?: string;
|
||||
hours_to_show?: number;
|
||||
}
|
||||
|
||||
@customElement("hui-sensor-card")
|
||||
class HuiSensorCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
@ -161,13 +151,13 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: SensorCardConfig;
|
||||
|
||||
@property() private _history?: any;
|
||||
|
||||
private _date?: Date;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: SensorCardConfig): void {
|
||||
if (!config.entity || config.entity.split(".")[0] !== "sensor") {
|
||||
throw new Error("Specify an entity from within the sensor domain.");
|
||||
}
|
||||
@ -272,6 +262,14 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
|
||||
this._date = new Date();
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
if (changedProps.has("_history")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (!this._config || this._config.graph !== "line" || !this.hass) {
|
||||
|
@ -16,7 +16,6 @@ import "../../../components/ha-icon";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import {
|
||||
fetchItems,
|
||||
updateItem,
|
||||
@ -24,10 +23,7 @@ import {
|
||||
clearItems,
|
||||
addItem,
|
||||
} from "../../../data/shopping-list";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
}
|
||||
import { ShoppingListCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-shopping-list-card")
|
||||
class HuiShoppingListCard extends LitElement implements LovelaceCard {
|
||||
@ -42,7 +38,7 @@ class HuiShoppingListCard extends LitElement implements LovelaceCard {
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: ShoppingListCardConfig;
|
||||
|
||||
@property() private _uncheckedItems?: ShoppingListItem[];
|
||||
|
||||
@ -54,7 +50,7 @@ class HuiShoppingListCard extends LitElement implements LovelaceCard {
|
||||
return (this._config ? (this._config.title ? 1 : 0) : 0) + 3;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ShoppingListCardConfig): void {
|
||||
this._config = config;
|
||||
this._uncheckedItems = [];
|
||||
this._checkedItems = [];
|
||||
|
@ -1,14 +1,10 @@
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import { createCardElement } from "../common/create-card-element";
|
||||
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
interface Config extends LovelaceCardConfig {
|
||||
cards: LovelaceCardConfig[];
|
||||
}
|
||||
import { StackCardConfig } from "./types";
|
||||
|
||||
export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
||||
static get properties() {
|
||||
@ -29,12 +25,12 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
}
|
||||
protected _cards?: LovelaceCard[];
|
||||
private _config?: Config;
|
||||
private _config?: StackCardConfig;
|
||||
private _hass?: HomeAssistant;
|
||||
|
||||
public abstract getCardSize(): number;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: StackCardConfig): void {
|
||||
if (!config || !config.cards || !Array.isArray(config.cards)) {
|
||||
throw new Error("Card config incorrect");
|
||||
}
|
||||
|
@ -19,10 +19,10 @@ import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { HomeAssistant, ClimateEntity } from "../../../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
||||
import { UNIT_F } from "../../../common/const";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { ThermostatCardConfig } from "./types";
|
||||
|
||||
const thermostatConfig = {
|
||||
radius: 150,
|
||||
@ -47,12 +47,6 @@ const modeIcons = {
|
||||
idle: "hass:power-sleep",
|
||||
};
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
theme?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
@customElement("hui-thermostat-card")
|
||||
export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
@ -66,7 +60,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: ThermostatCardConfig;
|
||||
|
||||
@property() private _roundSliderStyle?: TemplateResult;
|
||||
|
||||
@ -82,7 +76,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ThermostatCardConfig): void {
|
||||
if (!config.entity || config.entity.split(".")[0] !== "climate") {
|
||||
throw new Error("Specify an entity from within the climate domain.");
|
||||
}
|
||||
|
@ -2,12 +2,6 @@ import "../../../cards/ha-weather-card";
|
||||
|
||||
import LegacyWrapperCard from "./hui-legacy-wrapper-card";
|
||||
|
||||
// should be interface when converted to TS
|
||||
export const Config = {
|
||||
entity: "",
|
||||
name: "",
|
||||
};
|
||||
|
||||
class HuiWeatherForecastCard extends LegacyWrapperCard {
|
||||
static async getConfigElement() {
|
||||
await import(/* webpackChunkName: "hui-weather-forecast-card-editor" */ "../editor/config-elements/hui-weather-forecast-card-editor");
|
||||
|
200
src/panels/lovelace/cards/types.ts
Normal file
200
src/panels/lovelace/cards/types.ts
Normal file
@ -0,0 +1,200 @@
|
||||
import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { Condition } from "../common/validate-condition";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { LovelaceElementConfig } from "../elements/types";
|
||||
|
||||
export interface AlarmPanelCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
states?: string[];
|
||||
}
|
||||
|
||||
export interface ConditionalCardConfig extends LovelaceCardConfig {
|
||||
card: LovelaceCardConfig;
|
||||
conditions: Condition[];
|
||||
}
|
||||
|
||||
export interface EmptyStateCardConfig extends LovelaceCardConfig {
|
||||
content: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface EntitiesCardEntityConfig extends EntityConfig {
|
||||
type?: string;
|
||||
secondary_info?: "entity-id" | "last-changed";
|
||||
action_name?: string;
|
||||
service?: string;
|
||||
service_data?: object;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface EntitiesCardConfig extends LovelaceCardConfig {
|
||||
show_header_toggle?: boolean;
|
||||
title?: string;
|
||||
entities: EntitiesCardEntityConfig[];
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
export interface EntityButtonCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
show_name?: boolean;
|
||||
icon?: string;
|
||||
show_icon?: boolean;
|
||||
theme?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
||||
export interface EntityFilterCardConfig extends LovelaceCardConfig {
|
||||
type: "entity-filter";
|
||||
entities: Array<EntityConfig | string>;
|
||||
state_filter: string[];
|
||||
card: Partial<LovelaceCardConfig>;
|
||||
show_empty?: boolean;
|
||||
}
|
||||
|
||||
export interface ErrorCardConfig extends LovelaceCardConfig {
|
||||
error: string;
|
||||
origConfig: LovelaceCardConfig;
|
||||
}
|
||||
|
||||
export interface SeverityConfig {
|
||||
green?: number;
|
||||
yellow?: number;
|
||||
red?: number;
|
||||
}
|
||||
|
||||
export interface GaugeCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
unit?: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
severity?: SeverityConfig;
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
export interface ConfigEntity extends EntityConfig {
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
||||
export interface GlanceCardConfig extends LovelaceCardConfig {
|
||||
show_name?: boolean;
|
||||
show_state?: boolean;
|
||||
show_icon?: boolean;
|
||||
title?: string;
|
||||
theme?: string;
|
||||
entities: ConfigEntity[];
|
||||
columns?: number;
|
||||
}
|
||||
|
||||
export interface IframeCardConfig extends LovelaceCardConfig {
|
||||
aspect_ratio?: string;
|
||||
title?: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface LightCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
export interface MapCardConfig extends LovelaceCardConfig {
|
||||
title: string;
|
||||
aspect_ratio: string;
|
||||
default_zoom?: number;
|
||||
entities?: Array<EntityConfig | string>;
|
||||
geo_location_sources?: string[];
|
||||
}
|
||||
|
||||
export interface MarkdownCardConfig extends LovelaceCardConfig {
|
||||
content: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface MediaControlCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
}
|
||||
|
||||
export interface PictureCardConfig extends LovelaceCardConfig {
|
||||
image?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
||||
export interface PictureElementsCardConfig extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
state_image?: {};
|
||||
aspect_ratio?: string;
|
||||
entity?: string;
|
||||
elements: LovelaceElementConfig[];
|
||||
}
|
||||
|
||||
export interface PictureEntityCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
state_image?: {};
|
||||
aspect_ratio?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
show_name?: boolean;
|
||||
show_state?: boolean;
|
||||
}
|
||||
|
||||
export interface PictureGlanceCardConfig extends LovelaceCardConfig {
|
||||
entities: EntityConfig[];
|
||||
title?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
state_image?: {};
|
||||
aspect_ratio?: string;
|
||||
entity?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
||||
export interface PlantAttributeTarget extends EventTarget {
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export interface PlantStatusCardConfig extends LovelaceCardConfig {
|
||||
name?: string;
|
||||
entity: string;
|
||||
}
|
||||
|
||||
export interface SensorCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
icon?: string;
|
||||
graph?: string;
|
||||
unit?: string;
|
||||
detail?: number;
|
||||
theme?: string;
|
||||
hours_to_show?: number;
|
||||
}
|
||||
|
||||
export interface ShoppingListCardConfig extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface StackCardConfig extends LovelaceCardConfig {
|
||||
cards: LovelaceCardConfig[];
|
||||
}
|
||||
|
||||
export interface ThermostatCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
theme?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface WeatherForecastCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
}
|
@ -5,6 +5,7 @@ import {
|
||||
LovelaceViewConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { HassEntity, HassEntities } from "home-assistant-js-websocket";
|
||||
|
||||
import extractViews from "../../../common/entity/extract_views";
|
||||
import getViewEntities from "../../../common/entity/get_view_entities";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
@ -12,9 +13,10 @@ import splitByGroups from "../../../common/entity/split_by_groups";
|
||||
import computeObjectId from "../../../common/entity/compute_object_id";
|
||||
import computeStateDomain from "../../../common/entity/compute_state_domain";
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
|
||||
import { EntityRowConfig, WeblinkConfig } from "../entity-rows/types";
|
||||
import { EntitiesCardConfig } from "../cards/hui-entities-card";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import { EntitiesCardConfig } from "../cards/types";
|
||||
|
||||
const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
||||
const DOMAINS_BADGES = [
|
||||
|
@ -11,13 +11,11 @@ export function checkConditionsMet(
|
||||
hass: HomeAssistant
|
||||
): boolean {
|
||||
return conditions.every((c) => {
|
||||
if (!(c.entity in hass.states)) {
|
||||
return false;
|
||||
}
|
||||
if (c.state) {
|
||||
return hass.states[c.entity].state === c.state;
|
||||
}
|
||||
return hass!.states[c.entity].state !== c.state_not;
|
||||
const state = hass.states[c.entity]
|
||||
? hass!.states[c.entity].state
|
||||
: "unavailable";
|
||||
|
||||
return c.state ? state === c.state : state !== c.state_not;
|
||||
});
|
||||
}
|
||||
|
||||
|
26
src/panels/lovelace/components/dialog/ha-dialog.ts
Normal file
26
src/panels/lovelace/components/dialog/ha-dialog.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import { mixinBehaviors } from "@polymer/polymer/lib/legacy/class";
|
||||
import { HaIronFocusablesHelper } from "./ha-iron-focusables-helper.js";
|
||||
|
||||
const paperDialogClass = customElements.get("paper-dialog");
|
||||
|
||||
// behavior that will override existing iron-overlay-behavior and call the fixed implementation
|
||||
const haTabFixBehaviorImpl = {
|
||||
get _focusableNodes() {
|
||||
return HaIronFocusablesHelper.getTabbableNodes(this);
|
||||
},
|
||||
};
|
||||
|
||||
// paper-dialog that uses the haTabFixBehaviorImpl behvaior
|
||||
// export class HaPaperDialog extends paperDialogClass {}
|
||||
export class HaPaperDialog extends mixinBehaviors(
|
||||
[haTabFixBehaviorImpl],
|
||||
paperDialogClass
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-paper-dialog": HaPaperDialog;
|
||||
}
|
||||
}
|
||||
customElements.define("ha-paper-dialog", HaPaperDialog);
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
/*
|
||||
Fixes issue with not using shadow dom properly in iron-overlay-behavior/icon-focusables-helper.js
|
||||
*/
|
||||
import { dom } from "@polymer/polymer/lib/legacy/polymer.dom.js";
|
||||
|
||||
import { IronFocusablesHelper } from "@polymer/iron-overlay-behavior/iron-focusables-helper.js";
|
||||
|
||||
export const HaIronFocusablesHelper = {
|
||||
/**
|
||||
* Returns a sorted array of tabbable nodes, including the root node.
|
||||
* It searches the tabbable nodes in the light and shadow dom of the chidren,
|
||||
* sorting the result by tabindex.
|
||||
* @param {!Node} node
|
||||
* @return {!Array<!HTMLElement>}
|
||||
*/
|
||||
getTabbableNodes: function(node) {
|
||||
var result = [];
|
||||
// If there is at least one element with tabindex > 0, we need to sort
|
||||
// the final array by tabindex.
|
||||
var needsSortByTabIndex = this._collectTabbableNodes(node, result);
|
||||
if (needsSortByTabIndex) {
|
||||
return IronFocusablesHelper._sortByTabIndex(result);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Searches for nodes that are tabbable and adds them to the `result` array.
|
||||
* Returns if the `result` array needs to be sorted by tabindex.
|
||||
* @param {!Node} node The starting point for the search; added to `result`
|
||||
* if tabbable.
|
||||
* @param {!Array<!HTMLElement>} result
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
_collectTabbableNodes: function(node, result) {
|
||||
// If not an element or not visible, no need to explore children.
|
||||
if (
|
||||
node.nodeType !== Node.ELEMENT_NODE ||
|
||||
!IronFocusablesHelper._isVisible(node)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
var element = /** @type {!HTMLElement} */ (node);
|
||||
var tabIndex = IronFocusablesHelper._normalizedTabIndex(element);
|
||||
var needsSort = tabIndex > 0;
|
||||
if (tabIndex >= 0) {
|
||||
result.push(element);
|
||||
}
|
||||
|
||||
// In ShadowDOM v1, tab order is affected by the order of distrubution.
|
||||
// E.g. getTabbableNodes(#root) in ShadowDOM v1 should return [#A, #B];
|
||||
// in ShadowDOM v0 tab order is not affected by the distrubution order,
|
||||
// in fact getTabbableNodes(#root) returns [#B, #A].
|
||||
// <div id="root">
|
||||
// <!-- shadow -->
|
||||
// <slot name="a">
|
||||
// <slot name="b">
|
||||
// <!-- /shadow -->
|
||||
// <input id="A" slot="a">
|
||||
// <input id="B" slot="b" tabindex="1">
|
||||
// </div>
|
||||
// TODO(valdrin) support ShadowDOM v1 when upgrading to Polymer v2.0.
|
||||
var children;
|
||||
if (element.localName === "content" || element.localName === "slot") {
|
||||
children = dom(element).getDistributedNodes();
|
||||
} else {
|
||||
// /////////////////////////
|
||||
// Use shadow root if possible, will check for distributed nodes.
|
||||
// THIS IS THE CHANGED LINE
|
||||
children = dom(element.shadowRoot || element.root || element).children;
|
||||
// /////////////////////////
|
||||
}
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
// Ensure method is always invoked to collect tabbable children.
|
||||
needsSort = this._collectTabbableNodes(children[i], result) || needsSort;
|
||||
}
|
||||
return needsSort;
|
||||
},
|
||||
};
|
@ -9,15 +9,15 @@ import {
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntitiesCardEntityConfig } from "../cards/hui-entities-card";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
|
||||
import "../../../components/entity/state-badge";
|
||||
import "../../../components/ha-relative-time";
|
||||
import "../../../components/ha-icon";
|
||||
import "../components/hui-warning";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import { EntitiesCardEntityConfig } from "../cards/types";
|
||||
|
||||
class HuiGenericEntityRow extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
|
36
src/panels/lovelace/components/hui-warning-element.ts
Normal file
36
src/panels/lovelace/components/hui-warning-element.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
customElement,
|
||||
property,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/ha-icon";
|
||||
|
||||
@customElement("hui-warning-element")
|
||||
export class HuiWarningElement extends LitElement {
|
||||
@property() public label?: string;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<ha-icon icon="hass:alert" .title="${this.label}"></ha-icon>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
ha-icon {
|
||||
color: #fce588;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-warning-element": HuiWarningElement;
|
||||
}
|
||||
}
|
@ -96,6 +96,10 @@ export class HuiYamlEditor extends HTMLElement {
|
||||
tabSize: 2,
|
||||
autofocus: true,
|
||||
viewportMargin: Infinity,
|
||||
extraKeys: {
|
||||
Tab: "indentMore",
|
||||
"Shift-Tab": "indentLess",
|
||||
},
|
||||
gutters:
|
||||
this._hass && computeRTL(this._hass!)
|
||||
? ["rtl-gutter", "CodeMirror-linenumbers"]
|
||||
|
@ -1,60 +0,0 @@
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
|
||||
import "./hui-notification-item-template";
|
||||
|
||||
import EventsMixin from "../../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
export class HuiConfiguratorNotificationItem extends EventsMixin(
|
||||
LocalizeMixin(PolymerElement)
|
||||
) {
|
||||
static get template() {
|
||||
return html`
|
||||
<hui-notification-item-template>
|
||||
<span slot="header">[[localize('domain.configurator')]]</span>
|
||||
|
||||
<div>[[_getMessage(notification)]]</div>
|
||||
|
||||
<mwc-button slot="actions" on-click="_handleClick"
|
||||
>[[_localizeState(notification.state)]]</mwc-button
|
||||
>
|
||||
</hui-notification-item-template>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
notification: Object,
|
||||
};
|
||||
}
|
||||
|
||||
_handleClick() {
|
||||
this.fire("hass-more-info", { entityId: this.notification.entity_id });
|
||||
}
|
||||
|
||||
_localizeState(state) {
|
||||
return this.localize(`state.configurator.${state}`);
|
||||
}
|
||||
|
||||
_getMessage(notification) {
|
||||
const friendlyName = notification.attributes.friendly_name;
|
||||
return this.localize(
|
||||
"ui.notification_drawer.click_to_configure",
|
||||
"entity",
|
||||
friendlyName
|
||||
);
|
||||
}
|
||||
}
|
||||
customElements.define(
|
||||
"hui-configurator-notification-item",
|
||||
HuiConfiguratorNotificationItem
|
||||
);
|
@ -0,0 +1,59 @@
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
property,
|
||||
customElement,
|
||||
} from "lit-element";
|
||||
import "@material/mwc-button";
|
||||
|
||||
import "./hui-notification-item-template";
|
||||
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
@customElement("hui-configurator-notification-item")
|
||||
export class HuiConfiguratorNotificationItem extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() public notification?: HassEntity;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this.notification) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<hui-notification-item-template>
|
||||
<span slot="header">${this.hass.localize("domain.configurator")}</span>
|
||||
|
||||
<div>
|
||||
${this.hass.localize(
|
||||
"ui.notification_drawer.click_to_configure",
|
||||
"entity",
|
||||
this.notification.attributes.friendly_name
|
||||
)}
|
||||
</div>
|
||||
|
||||
<mwc-button slot="actions" @click="${this._handleClick}"
|
||||
>${this.hass.localize(
|
||||
`state.configurator.${this.notification.state}`
|
||||
)}</mwc-button
|
||||
>
|
||||
</hui-notification-item-template>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleClick(): void {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: this.notification!.entity_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-configurator-notification-item": HuiConfiguratorNotificationItem;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import computeDomain from "../../../../common/entity/compute_domain";
|
||||
|
||||
import "./hui-configurator-notification-item";
|
||||
import "./hui-persistent-notification-item";
|
||||
|
||||
export class HuiNotificationItem extends PolymerElement {
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
notification: {
|
||||
type: Object,
|
||||
observer: "_stateChanged",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_stateChanged(notification) {
|
||||
if (this.lastChild) {
|
||||
this.removeChild(this.lastChild);
|
||||
}
|
||||
|
||||
if (!notification) return;
|
||||
|
||||
const domain = notification.entity_id
|
||||
? computeDomain(notification.entity_id)
|
||||
: "persistent_notification";
|
||||
const tag = `hui-${domain}-notification-item`;
|
||||
const el = document.createElement(tag);
|
||||
el.hass = this.hass;
|
||||
el.notification = notification;
|
||||
this.appendChild(el);
|
||||
}
|
||||
}
|
||||
customElements.define("hui-notification-item", HuiNotificationItem);
|
@ -0,0 +1,55 @@
|
||||
import {
|
||||
LitElement,
|
||||
property,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
html,
|
||||
} from "lit-element";
|
||||
|
||||
import "./hui-configurator-notification-item";
|
||||
import "./hui-persistent-notification-item";
|
||||
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
|
||||
@customElement("hui-notification-item")
|
||||
export class HuiNotificationItem extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() public notification?: HassEntity;
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
if (!this.hass || !this.notification || changedProps.has("notification")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this.notification) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return this.notification.entity_id
|
||||
? html`
|
||||
<hui-configurator-notification-item
|
||||
.hass="${this.hass}"
|
||||
.notification="${this.notification}"
|
||||
></hui-configurator-notification-item>
|
||||
`
|
||||
: html`
|
||||
<hui-persistent-notification-item
|
||||
.hass="${this.hass}"
|
||||
.notification="${this.notification}"
|
||||
></hui-persistent-notification-item>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-notification-item": HuiNotificationItem;
|
||||
}
|
||||
}
|
@ -87,6 +87,6 @@ export class HuiPersistentNotificationItem extends LocalizeMixin(
|
||||
}
|
||||
}
|
||||
customElements.define(
|
||||
"hui-persistent_notification-notification-item",
|
||||
"hui-persistent-notification-item",
|
||||
HuiPersistentNotificationItem
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import "./hui-edit-card";
|
||||
import "./hui-dialog-pick-card";
|
||||
import { EditCardDialogParams } from "./show-edit-card-dialog";
|
||||
import { addCard, replaceCard } from "../config-util";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -32,19 +33,22 @@ export class HuiDialogEditCard extends LitElement {
|
||||
|
||||
@property() private _cardConfig?: LovelaceCardConfig;
|
||||
|
||||
@property() private _newCard?: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._cardPicked = this._cardPicked.bind(this);
|
||||
this._cancel = this._cancel.bind(this);
|
||||
this._save = this._save.bind(this);
|
||||
}
|
||||
|
||||
public async showDialog(params: EditCardDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
const [view, card] = params.path;
|
||||
this._newCard = card !== undefined ? false : true;
|
||||
this._cardConfig =
|
||||
params.path.length === 2
|
||||
? (this._cardConfig = params.lovelace.config.views[
|
||||
params.path[0]
|
||||
].cards![params.path[1]])
|
||||
card !== undefined
|
||||
? params.lovelace.config.views[view].cards![card]
|
||||
: undefined;
|
||||
}
|
||||
|
||||
@ -66,9 +70,10 @@ export class HuiDialogEditCard extends LitElement {
|
||||
<hui-edit-card
|
||||
.hass="${this.hass}"
|
||||
.lovelace="${this._params.lovelace}"
|
||||
.path="${this._params.path}"
|
||||
.cardConfig="${this._cardConfig}"
|
||||
.closeDialog="${this._cancel}"
|
||||
.saveCard="${this._save}"
|
||||
.newCard="${this._newCard}"
|
||||
>
|
||||
</hui-edit-card>
|
||||
`;
|
||||
@ -82,6 +87,19 @@ export class HuiDialogEditCard extends LitElement {
|
||||
this._params = undefined;
|
||||
this._cardConfig = undefined;
|
||||
}
|
||||
|
||||
private async _save(cardConf: LovelaceCardConfig): Promise<void> {
|
||||
const lovelace = this._params!.lovelace;
|
||||
await lovelace.saveConfig(
|
||||
this._params!.path.length === 1
|
||||
? addCard(lovelace.config, this._params!.path as [number], cardConf)
|
||||
: replaceCard(
|
||||
lovelace.config,
|
||||
this._params!.path as [number, number],
|
||||
cardConf
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -15,9 +15,10 @@ import { haStyleDialog } from "../../../../resources/styles";
|
||||
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "../../components/dialog/ha-dialog";
|
||||
// This is not a duplicate import, one is for types, one is for element.
|
||||
// tslint:disable-next-line
|
||||
import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
import { HaPaperDialog } from "../../components/dialog/ha-dialog";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
@ -33,10 +34,9 @@ import "./hui-card-preview";
|
||||
// tslint:disable-next-line
|
||||
import { HuiCardPreview } from "./hui-card-preview";
|
||||
import { LovelaceCardEditor, Lovelace } from "../../types";
|
||||
import { ConfigValue, ConfigError } from "../types";
|
||||
import { ConfigError } from "../types";
|
||||
import { EntityConfig } from "../../entity-rows/types";
|
||||
import { getCardElementTag } from "../../common/get-card-element-tag";
|
||||
import { addCard, replaceCard } from "../config-util";
|
||||
import { afterNextRender } from "../../../../common/util/render-status";
|
||||
|
||||
declare global {
|
||||
@ -58,15 +58,17 @@ export class HuiEditCard extends LitElement {
|
||||
|
||||
public lovelace?: Lovelace;
|
||||
|
||||
public path?: [number] | [number, number];
|
||||
|
||||
public closeDialog?: () => void;
|
||||
|
||||
public saveCard?: (cardConf: LovelaceCardConfig) => Promise<void>;
|
||||
|
||||
public newCard?: boolean;
|
||||
|
||||
@property() private _configElement?: LovelaceCardEditor | null;
|
||||
|
||||
@property() private _uiEditor?: boolean;
|
||||
|
||||
@property() private _configValue?: ConfigValue;
|
||||
@property() private _cardConfig?: LovelaceCardConfig;
|
||||
|
||||
@property() private _configState?: string;
|
||||
|
||||
@ -76,16 +78,28 @@ export class HuiEditCard extends LitElement {
|
||||
|
||||
@property() private _errorMsg?: TemplateResult;
|
||||
|
||||
private _cardType?: string;
|
||||
|
||||
private get _dialog(): PaperDialogElement {
|
||||
return this.shadowRoot!.querySelector("paper-dialog")!;
|
||||
private get _dialog(): HaPaperDialog {
|
||||
return this.shadowRoot!.querySelector("ha-paper-dialog")!;
|
||||
}
|
||||
|
||||
private get _previewEl(): HuiCardPreview {
|
||||
return this.shadowRoot!.querySelector("hui-card-preview")!;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line
|
||||
private __cardYaml: string | undefined;
|
||||
|
||||
private get _cardYaml(): string | undefined {
|
||||
if (!this.__cardYaml) {
|
||||
this.__cardYaml = yaml.safeDump(this._cardConfig);
|
||||
}
|
||||
return this.__cardYaml;
|
||||
}
|
||||
|
||||
private set _cardYaml(yml: string | undefined) {
|
||||
this.__cardYaml = yml;
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._saving = false;
|
||||
@ -98,7 +112,8 @@ export class HuiEditCard extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
this._configValue = { format: "yaml", value: undefined };
|
||||
this._cardConfig = undefined;
|
||||
this._cardYaml = undefined;
|
||||
this._configState = "OK";
|
||||
this._uiEditor = true;
|
||||
this._errorMsg = undefined;
|
||||
@ -119,7 +134,7 @@ export class HuiEditCard extends LitElement {
|
||||
: html`
|
||||
<hui-yaml-editor
|
||||
.hass="${this.hass}"
|
||||
.value="${this._configValue!.value}"
|
||||
.value="${this._cardYaml}"
|
||||
@yaml-changed="${this._handleYamlChanged}"
|
||||
@yaml-save="${this._save}"
|
||||
></hui-yaml-editor>
|
||||
@ -133,7 +148,7 @@ export class HuiEditCard extends LitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<paper-dialog
|
||||
<ha-paper-dialog
|
||||
with-backdrop
|
||||
opened
|
||||
modal
|
||||
@ -162,7 +177,6 @@ export class HuiEditCard extends LitElement {
|
||||
<div class="paper-dialog-buttons">
|
||||
<mwc-button
|
||||
class="toggle-button"
|
||||
?hidden="${!this._configValue || !this._configValue.value}"
|
||||
?disabled="${this._configElement === null ||
|
||||
this._configState !== "OK"}"
|
||||
@click="${this._toggleEditor}"
|
||||
@ -174,7 +188,6 @@ export class HuiEditCard extends LitElement {
|
||||
>${this.hass!.localize("ui.common.cancel")}</mwc-button
|
||||
>
|
||||
<mwc-button
|
||||
?hidden="${!this._configValue || !this._configValue.value}"
|
||||
?disabled="${this._saving || this._configState !== "OK"}"
|
||||
@click="${this._save}"
|
||||
>
|
||||
@ -187,7 +200,7 @@ export class HuiEditCard extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</paper-dialog>
|
||||
</ha-paper-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -206,7 +219,7 @@ export class HuiEditCard extends LitElement {
|
||||
|
||||
private async _resizeDialog(): Promise<void> {
|
||||
await this.updateComplete;
|
||||
fireEvent(this._dialog, "iron-resize");
|
||||
fireEvent(this._dialog as HTMLElement, "iron-resize");
|
||||
}
|
||||
|
||||
private async _save(): Promise<void> {
|
||||
@ -222,22 +235,9 @@ export class HuiEditCard extends LitElement {
|
||||
|
||||
this._saving = true;
|
||||
|
||||
const cardConf: LovelaceCardConfig =
|
||||
this._configValue!.format === "yaml"
|
||||
? yaml.safeLoad(this._configValue!.value!)
|
||||
: this._configValue!.value!;
|
||||
|
||||
try {
|
||||
const lovelace = this.lovelace!;
|
||||
await lovelace.saveConfig(
|
||||
this._creatingCard
|
||||
? addCard(lovelace.config, this.path as [number], cardConf)
|
||||
: replaceCard(
|
||||
lovelace.config,
|
||||
this.path as [number, number],
|
||||
cardConf
|
||||
)
|
||||
);
|
||||
await this.saveCard!(this._cardConfig!);
|
||||
this._cardYaml = undefined;
|
||||
this.closeDialog!();
|
||||
} catch (err) {
|
||||
alert(`Saving failed: ${err.message}`);
|
||||
@ -247,12 +247,9 @@ export class HuiEditCard extends LitElement {
|
||||
}
|
||||
|
||||
private _handleYamlChanged(ev: CustomEvent): void {
|
||||
this._configValue = { format: "yaml", value: ev.detail.value };
|
||||
this._cardConfig = yaml.safeLoad(ev.detail.value);
|
||||
try {
|
||||
const config = yaml.safeLoad(
|
||||
this._configValue.value
|
||||
) as LovelaceCardConfig;
|
||||
this._updatePreview(config);
|
||||
this._updatePreview(this._cardConfig!);
|
||||
this._configState = "OK";
|
||||
} catch (err) {
|
||||
this._configState = "YAML_ERROR";
|
||||
@ -264,7 +261,7 @@ export class HuiEditCard extends LitElement {
|
||||
}
|
||||
|
||||
private _handleUIConfigChanged(value: LovelaceCardConfig): void {
|
||||
this._configValue = { format: "json", value };
|
||||
this._cardConfig = value;
|
||||
this._updatePreview(value);
|
||||
}
|
||||
|
||||
@ -294,35 +291,23 @@ export class HuiEditCard extends LitElement {
|
||||
}
|
||||
|
||||
private async _toggleEditor(): Promise<void> {
|
||||
if (this._uiEditor && this._configValue!.format === "json") {
|
||||
this._configValue = {
|
||||
format: "yaml",
|
||||
value: yaml.safeDump(this._configValue!.value),
|
||||
};
|
||||
this._uiEditor = !this._uiEditor;
|
||||
} else if (this._configElement && this._configValue!.format === "yaml") {
|
||||
const yamlConfig = this._configValue!.value;
|
||||
const cardConfig = yaml.safeLoad(yamlConfig) as LovelaceCardConfig;
|
||||
this._uiEditor = !this._uiEditor;
|
||||
if (cardConfig.type !== this._cardType) {
|
||||
const succes = await this._loadConfigElement(cardConfig);
|
||||
if (!succes) {
|
||||
this._loadedDialog();
|
||||
}
|
||||
this._cardType = cardConfig.type;
|
||||
this._cardYaml = undefined;
|
||||
if (this._uiEditor) {
|
||||
this._uiEditor = false;
|
||||
} else if (this._configElement) {
|
||||
const success = await this._loadConfigElement(this._cardConfig!);
|
||||
if (!success) {
|
||||
this._loadedDialog();
|
||||
} else {
|
||||
this._configValue = {
|
||||
format: "json",
|
||||
value: cardConfig,
|
||||
};
|
||||
this._configElement.setConfig(cardConfig);
|
||||
this._uiEditor = true;
|
||||
this._configElement.setConfig(this._cardConfig!);
|
||||
}
|
||||
}
|
||||
this._resizeDialog();
|
||||
}
|
||||
|
||||
private _isConfigValid(): boolean {
|
||||
if (!this._configValue || !this._configValue.value) {
|
||||
if (!this._cardConfig) {
|
||||
return false;
|
||||
}
|
||||
if (this._configState === "OK") {
|
||||
@ -333,14 +318,10 @@ export class HuiEditCard extends LitElement {
|
||||
}
|
||||
|
||||
private _isConfigChanged(): boolean {
|
||||
if (this._creatingCard) {
|
||||
if (this.newCard) {
|
||||
return true;
|
||||
}
|
||||
const configValue =
|
||||
this._configValue!.format === "yaml"
|
||||
? yaml.safeLoad(this._configValue!.value)
|
||||
: this._configValue!.value;
|
||||
return JSON.stringify(configValue) !== JSON.stringify(this.cardConfig);
|
||||
return JSON.stringify(this._cardConfig) !== JSON.stringify(this.cardConfig);
|
||||
}
|
||||
|
||||
private async _loadConfigElement(conf: LovelaceCardConfig): Promise<boolean> {
|
||||
@ -357,10 +338,11 @@ export class HuiEditCard extends LitElement {
|
||||
const elClass = customElements.get(tag);
|
||||
let configElement;
|
||||
|
||||
this._cardConfig = conf;
|
||||
|
||||
if (elClass && elClass.getConfigElement) {
|
||||
configElement = await elClass.getConfigElement();
|
||||
} else {
|
||||
this._configValue = { format: "yaml", value: yaml.safeDump(conf) };
|
||||
this._updatePreview(conf);
|
||||
this._uiEditor = false;
|
||||
this._configElement = null;
|
||||
@ -374,10 +356,6 @@ export class HuiEditCard extends LitElement {
|
||||
Your config is not supported by the UI editor:<br /><b>${err.message}</b
|
||||
><br />Falling back to YAML editor.
|
||||
`;
|
||||
this._configValue = {
|
||||
format: "yaml",
|
||||
value: yaml.safeDump(conf),
|
||||
};
|
||||
this._updatePreview(conf);
|
||||
this._uiEditor = false;
|
||||
this._configElement = null;
|
||||
@ -388,17 +366,12 @@ export class HuiEditCard extends LitElement {
|
||||
configElement.addEventListener("config-changed", (ev) =>
|
||||
this._handleUIConfigChanged(ev.detail.config)
|
||||
);
|
||||
this._configValue = { format: "json", value: conf };
|
||||
this._configElement = configElement;
|
||||
await this.updateComplete;
|
||||
this._updatePreview(conf);
|
||||
return true;
|
||||
}
|
||||
|
||||
private get _creatingCard(): boolean {
|
||||
return this.path!.length === 1;
|
||||
}
|
||||
|
||||
private _openedChanged(ev): void {
|
||||
if (!ev.detail.value) {
|
||||
this.closeDialog!();
|
||||
|
@ -16,11 +16,11 @@ import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-alarm-panel-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-icon";
|
||||
import { AlarmPanelCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -34,9 +34,9 @@ export class HuiAlarmPanelCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: AlarmPanelCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: AlarmPanelCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -10,23 +10,23 @@ import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
import "../../../../components/entity/state-badge";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon";
|
||||
|
||||
import { processEditorEntities } from "../process-editor-entities";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import {
|
||||
EntitiesCardConfig,
|
||||
EntitiesCardEntityConfig,
|
||||
} from "../../cards/hui-entities-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../../../components/entity/state-badge";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon";
|
||||
} from "../../cards/types";
|
||||
|
||||
const entitiesConfigStruct = struct.union([
|
||||
{
|
||||
|
@ -7,6 +7,10 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import {
|
||||
EntitiesEditorEvent,
|
||||
@ -16,19 +20,17 @@ import {
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-entity-button-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { ActionConfig } from "../../../../data/lovelace";
|
||||
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import { EntityButtonCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string?",
|
||||
name: "string?",
|
||||
show_name: "boolean?",
|
||||
icon: "string?",
|
||||
show_icon: "boolean?",
|
||||
tap_action: struct.optional(actionConfigStruct),
|
||||
hold_action: struct.optional(actionConfigStruct),
|
||||
theme: "string?",
|
||||
@ -39,9 +41,9 @@ export class HuiEntityButtonCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: EntityButtonCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: EntityButtonCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
@ -54,10 +56,18 @@ export class HuiEntityButtonCardEditor extends LitElement
|
||||
return this._config!.name || "";
|
||||
}
|
||||
|
||||
get _show_name(): boolean {
|
||||
return this._config!.show_name || true;
|
||||
}
|
||||
|
||||
get _icon(): string {
|
||||
return this._config!.icon || "";
|
||||
}
|
||||
|
||||
get _show_icon(): boolean {
|
||||
return this._config!.show_icon || true;
|
||||
}
|
||||
|
||||
get _tap_action(): ActionConfig {
|
||||
return this._config!.tap_action || { action: "more-info" };
|
||||
}
|
||||
@ -101,6 +111,20 @@ export class HuiEntityButtonCardEditor extends LitElement
|
||||
@value-changed="${this._valueChanged}"
|
||||
></paper-input>
|
||||
</div>
|
||||
<div class="side-by-side">
|
||||
<paper-toggle-button
|
||||
?checked="${this._config!.show_name !== false}"
|
||||
.configValue="${"show_name"}"
|
||||
@change="${this._valueChanged}"
|
||||
>Show Name?</paper-toggle-button
|
||||
>
|
||||
<paper-toggle-button
|
||||
?checked="${this._config!.show_icon !== false}"
|
||||
.configValue="${"show_icon"}"
|
||||
@change="${this._valueChanged}"
|
||||
>Show Icon?</paper-toggle-button
|
||||
>
|
||||
</div>
|
||||
<hui-theme-select-editor
|
||||
.hass="${this.hass}"
|
||||
.value="${this._theme}"
|
||||
@ -147,7 +171,12 @@ export class HuiEntityButtonCardEditor extends LitElement
|
||||
} else {
|
||||
this._config = {
|
||||
...this._config,
|
||||
[target.configValue!]: target.value ? target.value : target.config,
|
||||
[target.configValue!]:
|
||||
target.checked !== undefined
|
||||
? target.checked
|
||||
: target.value
|
||||
? target.value
|
||||
: target.config,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -10,16 +10,16 @@ import {
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config, SeverityConfig } from "../../cards/hui-gauge-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import { GaugeCardConfig, SeverityConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -37,11 +37,11 @@ export class HuiGaugeCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: GaugeCardConfig;
|
||||
|
||||
private _useSeverity?: boolean;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: GaugeCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._useSeverity = !!config.severity;
|
||||
this._config = config;
|
||||
|
@ -10,20 +10,20 @@ import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
import "../../../../components/entity/state-badge";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { processEditorEntities } from "../process-editor-entities";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { GlanceCardConfig, ConfigEntity } from "../../cards/hui-glance-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../../../components/entity/state-badge";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon";
|
||||
import { GlanceCardConfig, ConfigEntity } from "../../cards/types";
|
||||
|
||||
const entitiesConfigStruct = struct.union([
|
||||
{
|
||||
|
@ -12,8 +12,8 @@ import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-iframe-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { IframeCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -27,9 +27,9 @@ export class HuiIframeCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: IframeCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: IframeCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -7,16 +7,16 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-light-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import { LightCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -30,9 +30,9 @@ export class HuiLightCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: LightCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: LightCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -9,19 +9,19 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-input-list-editor";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { MapCardConfig } from "../../cards/hui-map-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { processEditorEntities } from "../process-editor-entities";
|
||||
import { EntityConfig } from "../../entity-rows/types";
|
||||
import { PolymerChangedEvent } from "../../../../polymer-types";
|
||||
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-input-list-editor";
|
||||
import { MapCardConfig } from "../../cards/types";
|
||||
|
||||
const entitiesConfigStruct = struct.union([
|
||||
{
|
||||
|
@ -13,8 +13,8 @@ import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-markdown-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { MarkdownCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -27,9 +27,9 @@ export class HuiMarkdownCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: MarkdownCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: MarkdownCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-media-control-card";
|
||||
import { MediaControlCardConfig } from "../../cards/hui-media-control-card";
|
||||
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
|
||||
@ -25,9 +25,9 @@ export class HuiMediaControlCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: MediaControlCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: MediaControlCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import "../../components/hui-action-editor";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import {
|
||||
EntitiesEditorEvent,
|
||||
@ -16,11 +18,9 @@ import {
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-picture-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { ActionConfig } from "../../../../data/lovelace";
|
||||
|
||||
import "../../components/hui-action-editor";
|
||||
import { PictureCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -34,9 +34,9 @@ export class HuiPictureCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: PictureCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: PictureCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -7,16 +7,16 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-icon";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-alarm-panel-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-icon";
|
||||
import { PlantStatusCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -29,9 +29,9 @@ export class HuiPlantStatusCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: PlantStatusCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: PlantStatusCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -10,16 +10,16 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-sensor-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import { SensorCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -38,9 +38,9 @@ export class HuiSensorCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: SensorCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: SensorCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-shopping-list-card";
|
||||
import { ShoppingListCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -24,9 +24,9 @@ export class HuiShoppingListEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: ShoppingListCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ShoppingListCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -7,16 +7,16 @@ import {
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-thermostat-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import { ThermostatCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -30,9 +30,9 @@ export class HuiThermostatCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: ThermostatCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ThermostatCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -6,15 +6,15 @@ import {
|
||||
property,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config } from "../../cards/hui-weather-forecast-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import { WeatherForecastCardConfig } from "../../cards/types";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
@ -27,9 +27,9 @@ export class HuiWeatherForecastCardEditor extends LitElement
|
||||
implements LovelaceCardEditor {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: WeatherForecastCardConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: WeatherForecastCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
}
|
||||
|
@ -1,24 +1,21 @@
|
||||
import {
|
||||
Condition,
|
||||
checkConditionsMet,
|
||||
validateConditionalConfig,
|
||||
} from "../../lovelace/common/validate-condition";
|
||||
import { createStyledHuiElement } from "../cards/picture-elements/create-styled-hui-element";
|
||||
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import {
|
||||
LovelaceElement,
|
||||
LovelaceElementConfig,
|
||||
ConditionalElementConfig,
|
||||
} from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
interface Config extends LovelaceElementConfig {
|
||||
conditions: Condition[];
|
||||
elements: LovelaceElementConfig[];
|
||||
}
|
||||
|
||||
class HuiConditionalElement extends HTMLElement implements LovelaceElement {
|
||||
public _hass?: HomeAssistant;
|
||||
private _config?: Config;
|
||||
private _config?: ConditionalElementConfig;
|
||||
private _elements: LovelaceElement[] = [];
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ConditionalElementConfig): void {
|
||||
if (
|
||||
!config.conditions ||
|
||||
!Array.isArray(config.conditions) ||
|
||||
|
@ -13,24 +13,15 @@ import "../../../components/ha-icon";
|
||||
import { computeTooltip } from "../common/compute-tooltip";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { LovelaceElement, IconElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ActionConfig } from "../../../data/lovelace";
|
||||
|
||||
export interface Config extends LovelaceElementConfig {
|
||||
entity?: string;
|
||||
name?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
@customElement("hui-icon-element")
|
||||
export class HuiIconElement extends LitElement implements LovelaceElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() private _config?: Config;
|
||||
public hass?: HomeAssistant;
|
||||
@property() private _config?: IconElementConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: IconElementConfig): void {
|
||||
if (!config.icon) {
|
||||
throw Error("Invalid Configuration: 'icon' required");
|
||||
}
|
||||
|
@ -13,28 +13,15 @@ import "../components/hui-image";
|
||||
import { computeTooltip } from "../common/compute-tooltip";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { LovelaceElement, ImageElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ActionConfig } from "../../../data/lovelace";
|
||||
|
||||
export interface Config extends LovelaceElementConfig {
|
||||
entity?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
image?: string;
|
||||
state_image?: string;
|
||||
camera_image?: string;
|
||||
filter?: string;
|
||||
state_filter?: string;
|
||||
aspect_ratio?: string;
|
||||
}
|
||||
|
||||
@customElement("hui-image-element")
|
||||
export class HuiImageElement extends LitElement implements LovelaceElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: ImageElementConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ImageElementConfig): void {
|
||||
if (!config) {
|
||||
throw Error("Error in element configuration");
|
||||
}
|
||||
|
@ -10,20 +10,14 @@ import {
|
||||
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { LovelaceElement, ServiceButtonElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
export interface Config extends LovelaceElementConfig {
|
||||
title?: string;
|
||||
service?: string;
|
||||
service_data?: object;
|
||||
}
|
||||
|
||||
@customElement("hui-service-button-element")
|
||||
export class HuiServiceButtonElement extends LitElement
|
||||
implements LovelaceElement {
|
||||
public hass?: HomeAssistant;
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: ServiceButtonElementConfig;
|
||||
private _domain?: string;
|
||||
private _service?: string;
|
||||
|
||||
@ -31,7 +25,7 @@ export class HuiServiceButtonElement extends LitElement
|
||||
return { _config: {} };
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: ServiceButtonElementConfig): void {
|
||||
if (!config || !config.service) {
|
||||
throw Error("Invalid Configuration: 'service' required");
|
||||
}
|
||||
|
@ -4,26 +4,24 @@ import {
|
||||
TemplateResult,
|
||||
customElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/entity/ha-state-label-badge";
|
||||
import "../components/hui-warning";
|
||||
import "../components/hui-warning-element";
|
||||
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { LovelaceElement, StateBadgeElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
export interface Config extends LovelaceElementConfig {
|
||||
entity: string;
|
||||
}
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-state-badge-element")
|
||||
export class HuiStateBadgeElement extends LitElement
|
||||
implements LovelaceElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: StateBadgeElementConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: StateBadgeElementConfig): void {
|
||||
if (!config.entity) {
|
||||
throw Error("Invalid Configuration: 'entity' required");
|
||||
}
|
||||
@ -31,6 +29,10 @@ export class HuiStateBadgeElement extends LitElement
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
@ -40,13 +42,13 @@ export class HuiStateBadgeElement extends LitElement
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<hui-warning
|
||||
>${this.hass.localize(
|
||||
<hui-warning-element
|
||||
label="${this.hass.localize(
|
||||
"ui.panel.lovelace.warning.entity_not_found",
|
||||
"entity",
|
||||
this._config.entity
|
||||
)}</hui-warning
|
||||
>
|
||||
)}"
|
||||
></hui-warning-element>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -6,30 +6,25 @@ import {
|
||||
property,
|
||||
css,
|
||||
CSSResult,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/entity/state-badge";
|
||||
import "../components/hui-warning";
|
||||
import "../components/hui-warning-element";
|
||||
|
||||
import { computeTooltip } from "../common/compute-tooltip";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { LovelaceElement, StateIconElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ActionConfig } from "../../../data/lovelace";
|
||||
|
||||
export interface Config extends LovelaceElementConfig {
|
||||
entity: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-state-icon-element")
|
||||
export class HuiStateIconElement extends LitElement implements LovelaceElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: StateIconElementConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: StateIconElementConfig): void {
|
||||
if (!config.entity) {
|
||||
throw Error("Invalid Configuration: 'entity' required");
|
||||
}
|
||||
@ -37,6 +32,10 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
@ -46,13 +45,13 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<hui-warning
|
||||
>${this.hass.localize(
|
||||
<hui-warning-element
|
||||
label=${this.hass.localize(
|
||||
"ui.panel.lovelace.warning.entity_not_found",
|
||||
"entity",
|
||||
this._config.entity
|
||||
)}</hui-warning
|
||||
>
|
||||
)}
|
||||
></hui-warning-element>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -6,33 +6,26 @@ import {
|
||||
property,
|
||||
css,
|
||||
CSSResult,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/entity/ha-state-label-badge";
|
||||
import "../components/hui-warning";
|
||||
import "../components/hui-warning-element";
|
||||
|
||||
import computeStateDisplay from "../../../common/entity/compute_state_display";
|
||||
import { computeTooltip } from "../common/compute-tooltip";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { LovelaceElement, StateLabelElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ActionConfig } from "../../../data/lovelace";
|
||||
|
||||
interface Config extends LovelaceElementConfig {
|
||||
entity: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-state-label-element")
|
||||
class HuiStateLabelElement extends LitElement implements LovelaceElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() private _config?: Config;
|
||||
@property() private _config?: StateLabelElementConfig;
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: StateLabelElementConfig): void {
|
||||
if (!config.entity) {
|
||||
throw Error("Invalid Configuration: 'entity' required");
|
||||
}
|
||||
@ -40,6 +33,10 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
@ -49,13 +46,13 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<hui-warning
|
||||
>${this.hass.localize(
|
||||
<hui-warning-element
|
||||
label=${this.hass.localize(
|
||||
"ui.panel.lovelace.warning.entity_not_found",
|
||||
"entity",
|
||||
this._config.entity
|
||||
)}</hui-warning
|
||||
>
|
||||
)}
|
||||
></hui-warning-element>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { Condition } from "../common/validate-condition";
|
||||
import { ActionConfig } from "../../../data/lovelace";
|
||||
|
||||
export interface LovelaceElementConfig {
|
||||
type: string;
|
||||
@ -9,3 +11,52 @@ export interface LovelaceElement extends HTMLElement {
|
||||
hass?: HomeAssistant;
|
||||
setConfig(config: LovelaceElementConfig): void;
|
||||
}
|
||||
|
||||
export interface ConditionalElementConfig extends LovelaceElementConfig {
|
||||
conditions: Condition[];
|
||||
elements: LovelaceElementConfig[];
|
||||
}
|
||||
|
||||
export interface IconElementConfig extends LovelaceElementConfig {
|
||||
entity?: string;
|
||||
name?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export interface ImageElementConfig extends LovelaceElementConfig {
|
||||
entity?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
image?: string;
|
||||
state_image?: string;
|
||||
camera_image?: string;
|
||||
filter?: string;
|
||||
state_filter?: string;
|
||||
aspect_ratio?: string;
|
||||
}
|
||||
|
||||
export interface ServiceButtonElementConfig extends LovelaceElementConfig {
|
||||
title?: string;
|
||||
service?: string;
|
||||
service_data?: object;
|
||||
}
|
||||
|
||||
export interface StateBadgeElementConfig extends LovelaceElementConfig {
|
||||
entity: string;
|
||||
}
|
||||
|
||||
export interface StateIconElementConfig extends LovelaceElementConfig {
|
||||
entity: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
||||
export interface StateLabelElementConfig extends LovelaceElementConfig {
|
||||
entity: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/ha-climate-state";
|
||||
@ -14,6 +15,7 @@ import "../components/hui-warning";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-climate-entity-row")
|
||||
class HuiClimateEntityRow extends LitElement implements EntityRow {
|
||||
@ -29,6 +31,10 @@ class HuiClimateEntityRow extends LitElement implements EntityRow {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../components/hui-generic-entity-row";
|
||||
@ -16,6 +17,7 @@ import "../components/hui-warning";
|
||||
import { isTiltOnly } from "../../../util/cover-model";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-cover-entity-row")
|
||||
class HuiCoverEntityRow extends LitElement implements EntityRow {
|
||||
@ -30,6 +32,10 @@ class HuiCoverEntityRow extends LitElement implements EntityRow {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
TemplateResult,
|
||||
property,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../components/hui-generic-entity-row";
|
||||
@ -11,9 +12,11 @@ import "../../../components/entity/ha-entity-toggle";
|
||||
import "../components/hui-warning";
|
||||
|
||||
import computeStateDisplay from "../../../common/entity/compute_state_display";
|
||||
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-group-entity-row")
|
||||
class HuiGroupEntityRow extends LitElement implements EntityRow {
|
||||
@ -28,6 +31,10 @@ class HuiGroupEntityRow extends LitElement implements EntityRow {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
customElement,
|
||||
css,
|
||||
CSSResult,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../components/hui-generic-entity-row";
|
||||
@ -16,6 +17,7 @@ import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { setValue } from "../../../data/input_text";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-input-number-entity-row")
|
||||
class HuiInputNumberEntityRow extends LitElement implements EntityRow {
|
||||
@ -48,6 +50,10 @@ class HuiInputNumberEntityRow extends LitElement implements EntityRow {
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { repeat } from "lit-html/directives/repeat";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
@ -16,9 +17,11 @@ import "../../../components/entity/state-badge";
|
||||
import "../components/hui-warning";
|
||||
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
import { setOption } from "../../../data/input-select";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-input-select-entity-row")
|
||||
class HuiInputSelectEntityRow extends LitElement implements EntityRow {
|
||||
@ -34,6 +37,10 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
TemplateResult,
|
||||
property,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||
|
||||
@ -13,6 +14,7 @@ import "../components/hui-warning";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
import { setValue } from "../../../data/input_text";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-input-text-entity-row")
|
||||
class HuiInputTextEntityRow extends LitElement implements EntityRow {
|
||||
@ -27,6 +29,10 @@ class HuiInputTextEntityRow extends LitElement implements EntityRow {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
|
||||
import "../components/hui-generic-entity-row";
|
||||
@ -13,6 +14,7 @@ import "../components/hui-warning";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-lock-entity-row")
|
||||
class HuiLockEntityRow extends LitElement implements EntityRow {
|
||||
@ -27,6 +29,10 @@ class HuiLockEntityRow extends LitElement implements EntityRow {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
CSSResult,
|
||||
property,
|
||||
customElement,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
@ -22,6 +23,7 @@ import {
|
||||
OFF_STATES,
|
||||
SUPPORT_PAUSE,
|
||||
} from "../../../data/media-player";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
@customElement("hui-media-player-entity-row")
|
||||
class HuiMediaPlayerEntityRow extends LitElement implements EntityRow {
|
||||
@ -37,6 +39,10 @@ class HuiMediaPlayerEntityRow extends LitElement implements EntityRow {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user