diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b89fc8e595..411ffee836 100755 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,8 +1,9 @@ { - "recommendations": [ - "dbaeumer.vscode-eslint", - "eg2.tslint", - "esbenp.prettier-vscode", - "bierner.lit-html" - ] + "recommendations": [ + "dbaeumer.vscode-eslint", + "ms-vscode.vscode-typescript-tslint-plugin", + "esbenp.prettier-vscode", + "bierner.lit-html", + "runem.lit-plugin" + ] } diff --git a/demo/src/custom-cards/ha-demo-card.ts b/demo/src/custom-cards/ha-demo-card.ts index 02ff4c1e78..fe3f7afe65 100644 --- a/demo/src/custom-cards/ha-demo-card.ts +++ b/demo/src/custom-cards/ha-demo-card.ts @@ -7,7 +7,7 @@ import { } from "lit-element"; import { until } from "lit-html/directives/until"; import "@polymer/paper-icon-button"; -import "@polymer/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-spinner/paper-spinner-lite"; import "../../../src/components/ha-card"; import "../../../src/components/ha-paper-icon-button-next"; @@ -84,7 +84,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
- Learn more about Home Assistant + Learn more about Home Assistant
@@ -145,12 +145,7 @@ export class HADemoCard extends LitElement implements LovelaceCard { } .actions { - padding-left: 5px; - } - - .actions paper-button { - color: var(--primary-color); - font-weight: 500; + padding-left: 8px; } `, ]; diff --git a/gallery/src/demos/demo-hui-picture-entity-card.ts b/gallery/src/demos/demo-hui-picture-entity-card.ts index 7940a5ad00..1378707e45 100644 --- a/gallery/src/demos/demo-hui-picture-entity-card.ts +++ b/gallery/src/demos/demo-hui-picture-entity-card.ts @@ -2,6 +2,17 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; import "../components/demo-cards"; +import { provideHass } from "../../../src/fake_data/provide_hass"; +import { getEntity } from "../../../src/fake_data/entity"; + +const ENTITIES = [ + getEntity("light", "kitchen_lights", "on", { + friendly_name: "Kitchen Lights", + }), + getEntity("light", "bed_light", "off", { + friendly_name: "Bed Light", + }), +]; const CONFIGS = [ { @@ -10,6 +21,8 @@ const CONFIGS = [ - type: picture-entity image: /images/kitchen.png entity: light.kitchen_lights + tap_action: + action: toggle `, }, { @@ -18,6 +31,8 @@ const CONFIGS = [ - type: picture-entity image: /images/bed.png entity: light.bed_light + tap_action: + action: toggle `, }, { @@ -68,7 +83,7 @@ const CONFIGS = [ class DemoPicEntity extends PolymerElement { static get template() { return html` - + `; } @@ -80,6 +95,12 @@ class DemoPicEntity extends PolymerElement { }, }; } + + public ready() { + super.ready(); + const hass = provideHass(this.$.demos); + hass.addEntities(ENTITIES); + } } customElements.define("demo-hui-picture-entity-card", DemoPicEntity); diff --git a/gallery/src/demos/demo-hui-picture-glance-card.ts b/gallery/src/demos/demo-hui-picture-glance-card.ts index 2ab8d7c32c..faae58bd7b 100644 --- a/gallery/src/demos/demo-hui-picture-glance-card.ts +++ b/gallery/src/demos/demo-hui-picture-glance-card.ts @@ -2,6 +2,25 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; import "../components/demo-cards"; +import { getEntity } from "../../../src/fake_data/entity"; +import { provideHass } from "../../../src/fake_data/provide_hass"; + +const ENTITIES = [ + getEntity("switch", "decorative_lights", "on", { + friendly_name: "Decorative Lights", + }), + getEntity("light", "ceiling_lights", "on", { + friendly_name: "Ceiling Lights", + }), + getEntity("binary_sensor", "movement_backyard", "on", { + friendly_name: "Movement Backyard", + device_class: "moving", + }), + getEntity("binary_sensor", "basement_floor_wet", "off", { + friendly_name: "Basement Floor Wet", + device_class: "moisture", + }), +]; const CONFIGS = [ { @@ -105,7 +124,7 @@ const CONFIGS = [ class DemoPicGlance extends PolymerElement { static get template() { return html` - + `; } @@ -117,6 +136,12 @@ class DemoPicGlance extends PolymerElement { }, }; } + + public ready() { + super.ready(); + const hass = provideHass(this.$.demos); + hass.addEntities(ENTITIES); + } } customElements.define("demo-hui-picture-glance-card", DemoPicGlance); diff --git a/gallery/src/demos/demo-util-long-press.ts b/gallery/src/demos/demo-util-long-press.ts index d3cd8ddfb0..5f09e3598f 100644 --- a/gallery/src/demos/demo-util-long-press.ts +++ b/gallery/src/demos/demo-util-long-press.ts @@ -1,5 +1,5 @@ import { html, LitElement, TemplateResult } from "lit-element"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "../../../src/components/ha-card"; import { longPress } from "../../../src/panels/lovelace/common/directives/long-press-directive"; @@ -11,13 +11,13 @@ export class DemoUtilLongPress extends LitElement { ${[1, 2, 3].map( () => html` - (long) press me! - + @@ -60,11 +60,6 @@ export class DemoUtilLongPress extends LitElement { margin-bottom: 16px; } - paper-button { - font-weight: bold; - color: var(--primary-color); - } - textarea { height: 50px; } diff --git a/gallery/webpack.config.js b/gallery/webpack.config.js index 763bed55c7..82a7008709 100644 --- a/gallery/webpack.config.js +++ b/gallery/webpack.config.js @@ -1,7 +1,7 @@ const path = require("path"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { babelLoaderConfig } = require("../config/babel.js"); -const webpackBase = require("../config/babel.js"); +const webpackBase = require("../config/webpack.js"); const isProd = process.env.NODE_ENV === "production"; const chunkFilename = isProd ? "chunk.[chunkhash].js" : "[name].chunk.js"; diff --git a/hassio/src/addon-view/hassio-addon-audio.js b/hassio/src/addon-view/hassio-addon-audio.js index b94fab20ef..d1a4011dda 100644 --- a/hassio/src/addon-view/hassio-addon-audio.js +++ b/hassio/src/addon-view/hassio-addon-audio.js @@ -1,6 +1,6 @@ import "web-animations-js/web-animations-next-lite.min"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; @@ -65,7 +65,7 @@ class HassioAddonAudio extends EventsMixin(PolymerElement) {
- Save + Save
`; diff --git a/hassio/src/addon-view/hassio-addon-config.js b/hassio/src/addon-view/hassio-addon-config.js index cdcaf8060d..a4061b8899 100644 --- a/hassio/src/addon-view/hassio-addon-config.js +++ b/hassio/src/addon-view/hassio-addon-config.js @@ -1,5 +1,5 @@ import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -50,8 +50,8 @@ class HassioAddonConfig extends PolymerElement { data="[[resetData]]" >Reset to defaults - SaveSave diff --git a/hassio/src/addon-view/hassio-addon-info.js b/hassio/src/addon-view/hassio-addon-info.js index d4977ecd98..792407116b 100644 --- a/hassio/src/addon-view/hassio-addon-info.js +++ b/hassio/src/addon-view/hassio-addon-info.js @@ -1,5 +1,5 @@ import "@polymer/iron-icon/iron-icon"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-toggle-button/paper-toggle-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; @@ -77,7 +77,7 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) { color: white; --paper-card-header-color: white; } - paper-card.warning paper-button { + paper-card.warning mwc-button { color: white !important; } .warning { @@ -169,7 +169,7 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) { >Update @@ -219,7 +219,7 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) { Protection mode on this addon is disabled! This gives the add-on full access to the entire system, which adds security risks, and could damage your system when used incorrectly. Only disable the protection mode if you know, need AND trust the source of this addon.
- Enable Protection mode + Enable Protection mode
@@ -250,7 +250,7 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) { @@ -337,8 +337,8 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
diff --git a/hassio/src/addon-view/hassio-addon-logs.js b/hassio/src/addon-view/hassio-addon-logs.js index d93be1750e..154630b01e 100644 --- a/hassio/src/addon-view/hassio-addon-logs.js +++ b/hassio/src/addon-view/hassio-addon-logs.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -24,7 +24,7 @@ class HassioAddonLogs extends PolymerElement {
- Refresh + Refresh
`; diff --git a/hassio/src/addon-view/hassio-addon-network.js b/hassio/src/addon-view/hassio-addon-network.js index 7cfb15f5a0..569972c81f 100644 --- a/hassio/src/addon-view/hassio-addon-network.js +++ b/hassio/src/addon-view/hassio-addon-network.js @@ -60,7 +60,7 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) { data="[[resetData]]" >Reset to defaults - Save + Save
`; diff --git a/hassio/src/dashboard/hassio-hass-update.js b/hassio/src/dashboard/hassio-hass-update.js index 20c224cb3e..aff95e523a 100644 --- a/hassio/src/dashboard/hassio-hass-update.js +++ b/hassio/src/dashboard/hassio-hass-update.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -56,7 +56,7 @@ class HassioHassUpdate extends PolymerElement { Release notesRelease notes diff --git a/hassio/src/snapshots/hassio-snapshot.js b/hassio/src/snapshots/hassio-snapshot.js index e36c4c1b5b..8ea0c0e4a6 100644 --- a/hassio/src/snapshots/hassio-snapshot.js +++ b/hassio/src/snapshots/hassio-snapshot.js @@ -1,5 +1,5 @@ import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import "@polymer/paper-dialog/paper-dialog"; @@ -123,12 +123,12 @@ class HassioSnapshot extends PolymerElement { class="download" title="Download snapshot" > - Restore selectedRestore selected diff --git a/hassio/src/snapshots/hassio-snapshots.js b/hassio/src/snapshots/hassio-snapshots.js index 1318853856..6bacf798a1 100644 --- a/hassio/src/snapshots/hassio-snapshots.js +++ b/hassio/src/snapshots/hassio-snapshots.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-input/paper-input"; @@ -90,10 +90,10 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
- CreateCreate
diff --git a/hassio/src/system/hassio-host-info.js b/hassio/src/system/hassio-host-info.js index 0b650e3e48..ac19fcb519 100644 --- a/hassio/src/system/hassio-host-info.js +++ b/hassio/src/system/hassio-host-info.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -39,7 +39,7 @@ class HassioHostInfo extends EventsMixin(PolymerElement) { color: var(--google-red-500); margin-top: 16px; } - paper-button.info { + mwc-button.info { max-width: calc(50% - 12px); } table.info { @@ -67,13 +67,13 @@ class HassioHostInfo extends EventsMixin(PolymerElement) { - + Hardware - + diff --git a/hassio/src/system/hassio-supervisor-log.js b/hassio/src/system/hassio-supervisor-log.js index 985cc2372c..e9b48c2e48 100644 --- a/hassio/src/system/hassio-supervisor-log.js +++ b/hassio/src/system/hassio-supervisor-log.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -24,7 +24,7 @@ class HassioSupervisorLog extends PolymerElement {
- Refresh + Refresh
`; diff --git a/hassio/src/system/hassio-system.js b/hassio/src/system/hassio-system.js index dbfa76241f..3b16ca068f 100644 --- a/hassio/src/system/hassio-system.js +++ b/hassio/src/system/hassio-system.js @@ -12,6 +12,7 @@ class HassioSystem extends PolymerElement { - [[localize('ui.card.persistent_notification.dismiss')]][[localize('ui.card.persistent_notification.dismiss')]] `; diff --git a/src/common/entity/domain_icon.ts b/src/common/entity/domain_icon.ts index 5c6ac2a181..9971b9e66c 100644 --- a/src/common/entity/domain_icon.ts +++ b/src/common/entity/domain_icon.ts @@ -28,6 +28,7 @@ const fixedIcons = { light: "hass:lightbulb", mailbox: "hass:mailbox", notify: "hass:comment-alert", + person: "hass:account", plant: "hass:flower", proximity: "hass:apple-safari", remote: "hass:remote", diff --git a/src/common/file/b64-to-blob.ts b/src/common/file/b64-to-blob.ts new file mode 100644 index 0000000000..969cfcae1a --- /dev/null +++ b/src/common/file/b64-to-blob.ts @@ -0,0 +1,20 @@ +// https://stackoverflow.com/a/16245768 +export const b64toBlob = (b64Data, contentType = "", sliceSize = 512) => { + const byteCharacters = atob(b64Data); + const byteArrays: Uint8Array[] = []; + + for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { + const slice = byteCharacters.slice(offset, offset + sliceSize); + + const byteNumbers = new Array(slice.length); + for (let i = 0; i < slice.length; i++) { + byteNumbers[i] = slice.charCodeAt(i); + } + + const byteArray = new Uint8Array(byteNumbers); + + byteArrays.push(byteArray); + } + + return new Blob(byteArrays, { type: contentType }); +}; diff --git a/src/components/buttons/ha-progress-button.js b/src/components/buttons/ha-progress-button.js index f7b6faccec..9f14d21d18 100644 --- a/src/components/buttons/ha-progress-button.js +++ b/src/components/buttons/ha-progress-button.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-spinner/paper-spinner"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -12,26 +12,22 @@ class HaProgressButton extends PolymerElement { display: inline-block; } - paper-button { + mwc-button { transition: all 1s; } - .success paper-button { - color: white; + .success mwc-button { + --mdc-theme-primary: white; background-color: var(--google-green-500); transition: none; } - .error paper-button { - color: white; + .error mwc-button { + --mdc-theme-primary: white; background-color: var(--google-red-500); transition: none; } - paper-button[disabled] { - color: #c8c8c8; - } - .progress { @apply --layout; @apply --layout-center-center; @@ -43,13 +39,13 @@ class HaProgressButton extends PolymerElement { }
- - + diff --git a/src/components/entity/ha-entities-picker.ts b/src/components/entity/ha-entities-picker.ts new file mode 100644 index 0000000000..684ef67dc1 --- /dev/null +++ b/src/components/entity/ha-entities-picker.ts @@ -0,0 +1,121 @@ +import { + LitElement, + TemplateResult, + property, + html, + customElement, +} from "lit-element"; +import "@polymer/paper-icon-button/paper-icon-button-light"; + +import { HomeAssistant } from "../../types"; +import { PolymerChangedEvent } from "../../polymer-types"; +import { fireEvent } from "../../common/dom/fire_event"; +import isValidEntityId from "../../common/entity/valid_entity_id"; + +import "./ha-entity-picker"; +// Not a duplicate, type import +// tslint:disable-next-line +import { HaEntityPickerEntityFilterFunc } from "./ha-entity-picker"; +import { HassEntity } from "home-assistant-js-websocket"; + +@customElement("ha-entities-picker") +class HaEntitiesPickerLight extends LitElement { + @property() public hass?: HomeAssistant; + @property() public value?: string[]; + @property({ attribute: "domain-filter" }) public domainFilter?: string; + @property({ attribute: "picked-entity-label" }) + public pickedEntityLabel?: string; + @property({ attribute: "pick-entity-label" }) public pickEntityLabel?: string; + + protected render(): TemplateResult | void { + if (!this.hass) { + return; + } + const currentEntities = this._currentEntities; + return html` + ${currentEntities.map( + (entityId) => html` +
+ +
+ ` + )} +
+ +
+ `; + } + + private _entityFilter: HaEntityPickerEntityFilterFunc = ( + stateObj: HassEntity + ) => !this.value || !this.value.includes(stateObj.entity_id); + + private get _currentEntities() { + return this.value || []; + } + + private async _updateEntities(entities) { + fireEvent(this, "value-changed", { + value: entities, + }); + + this.value = entities; + } + + private _entityChanged(event: PolymerChangedEvent) { + event.stopPropagation(); + const curValue = (event.currentTarget as any).curValue; + const newValue = event.detail.value; + if ( + newValue === curValue || + (newValue !== "" && !isValidEntityId(newValue)) + ) { + return; + } + if (newValue === "") { + this._updateEntities( + this._currentEntities.filter((ent) => ent !== curValue) + ); + } else { + this._updateEntities( + this._currentEntities.map((ent) => (ent === curValue ? newValue : ent)) + ); + } + } + + private async _addEntity(event: PolymerChangedEvent) { + event.stopPropagation(); + const toAdd = event.detail.value; + (event.currentTarget as any).value = ""; + if (!toAdd) { + return; + } + const currentEntities = this._currentEntities; + if (currentEntities.includes(toAdd)) { + return; + } + + this._updateEntities([...currentEntities, toAdd]); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-entities-picker": HaEntitiesPickerLight; + } +} diff --git a/src/components/entity/ha-entity-picker.js b/src/components/entity/ha-entity-picker.js deleted file mode 100644 index bc4765d8d7..0000000000 --- a/src/components/entity/ha-entity-picker.js +++ /dev/null @@ -1,179 +0,0 @@ -import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-input/paper-input"; -import "@polymer/paper-item/paper-icon-item"; -import "@polymer/paper-item/paper-item-body"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "@vaadin/vaadin-combo-box/vaadin-combo-box-light"; - -import "./state-badge"; - -import computeStateName from "../../common/entity/compute_state_name"; -import LocalizeMixin from "../../mixins/localize-mixin"; -import EventsMixin from "../../mixins/events-mixin"; - -/* - * @appliesMixin LocalizeMixin - */ -class HaEntityPicker extends EventsMixin(LocalizeMixin(PolymerElement)) { - static get template() { - return html` - - - - Clear - - - - - `; - } - - static get properties() { - return { - allowCustomEntity: { - type: Boolean, - value: false, - }, - hass: { - type: Object, - observer: "_hassChanged", - }, - _hass: Object, - _states: { - type: Array, - computed: "_computeStates(_hass, domainFilter, entityFilter)", - }, - autofocus: Boolean, - label: { - type: String, - }, - value: { - type: String, - notify: true, - }, - opened: { - type: Boolean, - value: false, - observer: "_openedChanged", - }, - domainFilter: { - type: String, - value: null, - }, - entityFilter: { - type: Function, - value: null, - }, - disabled: Boolean, - }; - } - - _computeLabel(label, localize) { - return label === undefined - ? localize("ui.components.entity.entity-picker.entity") - : label; - } - - _computeStates(hass, domainFilter, entityFilter) { - if (!hass) return []; - - let entityIds = Object.keys(hass.states); - - if (domainFilter) { - entityIds = entityIds.filter( - (eid) => eid.substr(0, eid.indexOf(".")) === domainFilter - ); - } - - let entities = entityIds.sort().map((key) => hass.states[key]); - - if (entityFilter) { - entities = entities.filter(entityFilter); - } - - return entities; - } - - _computeStateName(state) { - return computeStateName(state); - } - - _openedChanged(newVal) { - if (!newVal) { - this._hass = this.hass; - } - } - - _hassChanged(newVal) { - if (!this.opened) { - this._hass = newVal; - } - } - - _computeToggleIcon(opened) { - return opened ? "hass:menu-up" : "hass:menu-down"; - } - - _fireChanged(ev) { - ev.stopPropagation(); - this.fire("change"); - } -} - -customElements.define("ha-entity-picker", HaEntityPicker); diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts new file mode 100644 index 0000000000..53f0b74db2 --- /dev/null +++ b/src/components/entity/ha-entity-picker.ts @@ -0,0 +1,201 @@ +import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-item/paper-icon-item"; +import "@polymer/paper-item/paper-item-body"; +import "@vaadin/vaadin-combo-box/vaadin-combo-box-light"; +import memoizeOne from "memoize-one"; + +import "./state-badge"; + +import computeStateName from "../../common/entity/compute_state_name"; +import { + LitElement, + TemplateResult, + html, + css, + CSSResult, + property, + PropertyValues, +} from "lit-element"; +import { HomeAssistant } from "../../types"; +import { HassEntity } from "home-assistant-js-websocket"; +import { PolymerChangedEvent } from "../../polymer-types"; +import { fireEvent } from "../../common/dom/fire_event"; + +export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean; + +const rowRenderer = ( + root: HTMLElement, + _owner, + model: { item: HassEntity } +) => { + if (!root.firstElementChild) { + root.innerHTML = ` + + + + +
[[_computeStateName(item)]]
+
[[item.entity_id]]
+
+
+ `; + } + + root.querySelector("state-badge")!.stateObj = model.item; + root.querySelector(".name")!.textContent = computeStateName(model.item); + root.querySelector("[secondary]")!.textContent = model.item.entity_id; +}; + +class HaEntityPicker extends LitElement { + @property({ type: Boolean }) public autofocus?: boolean; + @property({ type: Boolean }) public disabled?: boolean; + @property({ type: Boolean, attribute: "allow-custom-entity" }) + public allowCustomEntity; + @property() public hass?: HomeAssistant; + @property() public label?: string; + @property() public value?: string; + @property({ attribute: "domain-filter" }) public domainFilter?: string; + @property() public entityFilter?: HaEntityPickerEntityFilterFunc; + @property({ type: Boolean }) private _opened?: boolean; + @property() private _hass?: HomeAssistant; + + private _getStates = memoizeOne( + ( + hass: this["hass"], + domainFilter: this["domainFilter"], + entityFilter: this["entityFilter"] + ) => { + let states: HassEntity[] = []; + + if (!hass) { + return []; + } + let entityIds = Object.keys(hass.states); + + if (domainFilter) { + entityIds = entityIds.filter( + (eid) => eid.substr(0, eid.indexOf(".")) === domainFilter + ); + } + + states = entityIds.sort().map((key) => hass!.states[key]); + + if (entityFilter) { + states = states.filter( + (stateObj) => + // We always want to include the entity of the current value + stateObj.entity_id === this.value || entityFilter!(stateObj) + ); + } + return states; + } + ); + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + + if (changedProps.has("hass") && !this._opened) { + this._hass = this.hass; + } + } + + protected render(): TemplateResult | void { + const states = this._getStates( + this._hass, + this.domainFilter, + this.entityFilter + ); + + return html` + + + ${this.value + ? html` + + Clear + + ` + : ""} + ${states.length > 0 + ? html` + + Toggle + + ` + : ""} + + + `; + } + + private get _value() { + return this.value || ""; + } + + private _openedChanged(ev: PolymerChangedEvent) { + this._opened = ev.detail.value; + } + + private _valueChanged(ev: PolymerChangedEvent) { + const newValue = ev.detail.value; + if (newValue !== this._value) { + this.value = ev.detail.value; + setTimeout(() => { + fireEvent(this, "value-changed", { value: this.value }); + fireEvent(this, "change"); + }, 0); + } + } + + static get styles(): CSSResult { + return css` + paper-input > paper-icon-button { + width: 24px; + height: 24px; + padding: 2px; + color: var(--secondary-text-color); + } + [hidden] { + display: none; + } + `; + } +} + +customElements.define("ha-entity-picker", HaEntityPicker); diff --git a/src/components/ha-card.js b/src/components/ha-card.js deleted file mode 100644 index 44e58f43e9..0000000000 --- a/src/components/ha-card.js +++ /dev/null @@ -1,42 +0,0 @@ -import "@polymer/paper-styles/element-styles/paper-material-styles"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -class HaCard extends PolymerElement { - static get template() { - return html` - - - - - `; - } - - static get properties() { - return { - header: String, - }; - } -} - -customElements.define("ha-card", HaCard); diff --git a/src/components/ha-card.ts b/src/components/ha-card.ts new file mode 100644 index 0000000000..917ec69f8d --- /dev/null +++ b/src/components/ha-card.ts @@ -0,0 +1,45 @@ +import { + css, + CSSResult, + html, + LitElement, + property, + TemplateResult, +} from "lit-element"; + +class HaCard extends LitElement { + @property() public header?: string; + + static get styles(): CSSResult { + return css` + :host { + background: var( + --ha-card-background, + var(--paper-card-background-color, white) + ); + border-radius: var(--ha-card-border-radius, 2px); + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), + 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); + color: var(--primary-text-color); + display: block; + transition: all 0.3s ease-out; + } + .header:not(:empty) { + font-size: 24px; + letter-spacing: -0.012em; + line-height: 32px; + opacity: 0.87; + padding: 24px 16px 16px; + } + `; + } + + protected render(): TemplateResult { + return html` +
${this.header}
+ + `; + } +} + +customElements.define("ha-card", HaCard); diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 4cc5aaddf9..6e6d5fc658 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -6,7 +6,6 @@ import { PropertyValues, property, } from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-item/paper-icon-item"; @@ -14,27 +13,12 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import "./ha-icon"; +import "../components/user/ha-user-badge"; import isComponentLoaded from "../common/config/is_component_loaded"; import { HomeAssistant, Panel } from "../types"; import { fireEvent } from "../common/dom/fire_event"; import { DEFAULT_PANEL } from "../common/const"; -const computeInitials = (name: string) => { - if (!name) { - return "user"; - } - return ( - name - .trim() - // Split by space and take first 3 words - .split(" ") - .slice(0, 3) - // Of each word, take first letter - .map((s) => s.substr(0, 1)) - .join("") - ); -}; - const computeUrl = (urlPath) => `/${urlPath}`; const computePanels = (hass: HomeAssistant) => { @@ -93,22 +77,13 @@ class HaSidebar extends LitElement { return html``; } - const initials = hass.user ? computeInitials(hass.user.name) : ""; - return html`
Home Assistant
${hass.user ? html` - 2, - })}" - > - - ${initials} + + ` : ""} @@ -344,23 +319,6 @@ class HaSidebar extends LitElement { .dev-tools a { color: var(--sidebar-icon-color); } - - .profile-badge { - /* for ripple */ - position: relative; - box-sizing: border-box; - width: 40px; - line-height: 40px; - border-radius: 50%; - text-align: center; - background-color: var(--light-primary-color); - text-decoration: none; - color: var(--primary-text-color); - } - - .profile-badge.long { - font-size: 80%; - } `; } } diff --git a/src/components/ha-vacuum-state.js b/src/components/ha-vacuum-state.js index fd8c9d7db7..556dac2619 100644 --- a/src/components/ha-vacuum-state.js +++ b/src/components/ha-vacuum-state.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -38,21 +38,19 @@ class HaVacuumState extends LocalizeMixin(PolymerElement) { static get template() { return html` - [[_computeLabel(stateObj.state, _interceptable)]][[_computeLabel(stateObj.state, _interceptable)]] `; } diff --git a/src/components/user/ha-user-badge.ts b/src/components/user/ha-user-badge.ts new file mode 100644 index 0000000000..a4bb8a5a31 --- /dev/null +++ b/src/components/user/ha-user-badge.ts @@ -0,0 +1,77 @@ +import { + LitElement, + TemplateResult, + css, + CSSResult, + html, + property, + customElement, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; +import { User } from "../../data/auth"; +import { CurrentUser } from "../../types"; + +const computeInitials = (name: string) => { + if (!name) { + return "user"; + } + return ( + name + .trim() + // Split by space and take first 3 words + .split(" ") + .slice(0, 3) + // Of each word, take first letter + .map((s) => s.substr(0, 1)) + .join("") + ); +}; + +@customElement("ha-user-badge") +class StateBadge extends LitElement { + @property() public user?: User | CurrentUser; + + protected render(): TemplateResult | void { + const user = this.user; + + const initials = user ? computeInitials(user.name) : "?"; + + return html` +
2, + })}" + > + ${initials} +
+ `; + } + + static get styles(): CSSResult { + return css` + .profile-badge { + display: inline-block; + box-sizing: border-box; + width: 40px; + line-height: 40px; + border-radius: 50%; + text-align: center; + background-color: var(--light-primary-color); + text-decoration: none; + color: var(--primary-text-color); + overflow: hidden; + } + + .profile-badge.long { + font-size: 80%; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-user-badge": StateBadge; + } +} diff --git a/src/components/user/ha-user-picker.ts b/src/components/user/ha-user-picker.ts new file mode 100644 index 0000000000..9fcc6db530 --- /dev/null +++ b/src/components/user/ha-user-picker.ts @@ -0,0 +1,104 @@ +import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-item/paper-icon-item"; +import "@polymer/paper-item/paper-item-body"; +import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; +import "@polymer/paper-listbox/paper-listbox"; +import memoizeOne from "memoize-one"; +import { + LitElement, + TemplateResult, + html, + css, + CSSResult, + property, +} from "lit-element"; +import { HomeAssistant } from "../../types"; +import { fireEvent } from "../../common/dom/fire_event"; +import { User, fetchUsers } from "../../data/auth"; +import compare from "../../common/string/compare"; + +class HaEntityPicker extends LitElement { + public hass?: HomeAssistant; + @property() public label?: string; + @property() public value?: string; + @property() public users?: User[]; + + private _sortedUsers = memoizeOne((users?: User[]) => { + if (!users || users.length === 1) { + return users || []; + } + const sorted = [...users]; + sorted.sort((a, b) => compare(a.name, b.name)); + return sorted; + }); + + protected render(): TemplateResult | void { + return html` + + + + No user + + ${this._sortedUsers(this.users).map( + (user) => html` + + + ${user.name} + + ` + )} + + + `; + } + + private get _value() { + return this.value || ""; + } + + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + if (this.users === undefined) { + fetchUsers(this.hass!).then((users) => { + this.users = users; + }); + } + } + + private _userChanged(ev) { + const newValue = ev.detail.item.dataset.userId; + + if (newValue !== this._value) { + this.value = ev.detail.value; + setTimeout(() => { + fireEvent(this, "value-changed", { value: newValue }); + fireEvent(this, "change"); + }, 0); + } + } + + static get styles(): CSSResult { + return css` + :host { + display: inline-block; + } + paper-dropdown-menu-light { + display: block; + } + paper-listbox { + min-width: 200px; + } + paper-icon-item { + cursor: pointer; + } + `; + } +} + +customElements.define("ha-user-picker", HaEntityPicker); diff --git a/src/data/auth.ts b/src/data/auth.ts index 52c3af9099..4ec1e57146 100644 --- a/src/data/auth.ts +++ b/src/data/auth.ts @@ -1,5 +1,26 @@ +import { HomeAssistant } from "../types"; + export interface AuthProvider { name: string; id: string; type: string; } + +interface Credential { + type: string; +} + +export interface User { + id: string; + name: string; + is_owner: boolean; + is_active: boolean; + system_generated: boolean; + group_ids: string[]; + credentials: Credential[]; +} + +export const fetchUsers = async (hass: HomeAssistant) => + hass.callWS({ + type: "config/auth/list", + }); diff --git a/src/data/camera.ts b/src/data/camera.ts new file mode 100644 index 0000000000..cde6abb596 --- /dev/null +++ b/src/data/camera.ts @@ -0,0 +1,12 @@ +import { HomeAssistant } from "../types"; + +export interface CameraThumbnail { + content_type: string; + content: string; +} + +export const fetchThumbnail = (hass: HomeAssistant, entityId: string) => + hass.callWS({ + type: "camera_thumbnail", + entity_id: entityId, + }); diff --git a/src/data/lovelace.ts b/src/data/lovelace.ts index 84edaa0472..fa638acb85 100644 --- a/src/data/lovelace.ts +++ b/src/data/lovelace.ts @@ -5,7 +5,6 @@ export interface LovelaceConfig { views: LovelaceViewConfig[]; background?: string; resources?: Array<{ type: "css" | "js" | "module" | "html"; url: string }>; - excluded_entities?: string[]; } export interface LovelaceViewConfig { @@ -34,7 +33,10 @@ export interface ToggleActionConfig { export interface CallServiceActionConfig { action: "call-service"; service: string; - service_data?: { [key: string]: any }; + service_data?: { + entity_id?: string | [string]; + [key: string]: any; + }; } export interface NavigateActionConfig { diff --git a/src/data/ws-user.ts b/src/data/ws-user.ts index 66be784eb8..2e171b8dab 100644 --- a/src/data/ws-user.ts +++ b/src/data/ws-user.ts @@ -3,12 +3,17 @@ import { Connection, getCollection, } from "home-assistant-js-websocket"; -import { User } from "../types"; +import { CurrentUser } from "../types"; export const userCollection = (conn: Connection) => - getCollection(conn, "_usr", () => getUser(conn) as Promise, undefined); + getCollection( + conn, + "_usr", + () => getUser(conn) as Promise, + undefined + ); export const subscribeUser = ( conn: Connection, - onChange: (user: User) => void + onChange: (user: CurrentUser) => void ) => userCollection(conn).subscribe(onChange); diff --git a/src/data/zha.ts b/src/data/zha.ts index f5a67dbb12..8c50b82f3c 100644 --- a/src/data/zha.ts +++ b/src/data/zha.ts @@ -7,8 +7,19 @@ export interface ZHADeviceEntity extends HassEntity { }; } -export interface ZHAEntities { - [key: string]: HassEntity[]; +export interface ZHAEntityReference extends HassEntity { + name: string; +} + +export interface ZHADevice { + name: string; + ieee: string; + manufacturer: string; + model: string; + quirk_applied: boolean; + quirk_class: string; + entities: ZHAEntityReference[]; + manufacturer_code: number; } export interface Attribute { @@ -19,6 +30,7 @@ export interface Attribute { export interface Cluster { name: string; id: number; + endpoint_id: number; type: string; } @@ -29,7 +41,8 @@ export interface Command { } export interface ReadAttributeServiceData { - entity_id: string; + ieee: string; + endpoint_id: number; cluster_id: number; cluster_type: string; attribute: number; @@ -41,64 +54,60 @@ export const reconfigureNode = ( ieeeAddress: string ): Promise => hass.callWS({ - type: "zha/nodes/reconfigure", + type: "zha/devices/reconfigure", ieee: ieeeAddress, }); export const fetchAttributesForCluster = ( hass: HomeAssistant, - entityId: string, ieeeAddress: string, + endpointId: number, clusterId: number, clusterType: string ): Promise => hass.callWS({ - type: "zha/entities/clusters/attributes", - entity_id: entityId, + type: "zha/devices/clusters/attributes", ieee: ieeeAddress, + endpoint_id: endpointId, cluster_id: clusterId, cluster_type: clusterType, }); +export const fetchDevices = (hass: HomeAssistant): Promise => + hass.callWS({ + type: "zha/devices", + }); + export const readAttributeValue = ( hass: HomeAssistant, data: ReadAttributeServiceData ): Promise => { return hass.callWS({ ...data, - type: "zha/entities/clusters/attributes/value", + type: "zha/devices/clusters/attributes/value", }); }; export const fetchCommandsForCluster = ( hass: HomeAssistant, - entityId: string, ieeeAddress: string, + endpointId: number, clusterId: number, clusterType: string ): Promise => hass.callWS({ - type: "zha/entities/clusters/commands", - entity_id: entityId, + type: "zha/devices/clusters/commands", ieee: ieeeAddress, + endpoint_id: endpointId, cluster_id: clusterId, cluster_type: clusterType, }); export const fetchClustersForZhaNode = ( hass: HomeAssistant, - entityId: string, ieeeAddress: string ): Promise => hass.callWS({ - type: "zha/entities/clusters", - entity_id: entityId, + type: "zha/devices/clusters", ieee: ieeeAddress, }); - -export const fetchEntitiesForZhaNode = ( - hass: HomeAssistant -): Promise => - hass.callWS({ - type: "zha/entities", - }); diff --git a/src/dialogs/ha-store-auth-card.js b/src/dialogs/ha-store-auth-card.js index 9284e175f0..d63d805498 100644 --- a/src/dialogs/ha-store-auth-card.js +++ b/src/dialogs/ha-store-auth-card.js @@ -18,6 +18,10 @@ class HaStoreAuth extends LocalizeMixin(PolymerElement) { right: 16px; } + .card-content { + color: var(--primary-text-color); + } + .card-actions { text-align: right; border-top: 0; @@ -33,11 +37,11 @@ class HaStoreAuth extends LocalizeMixin(PolymerElement) {
[[localize('ui.auth_store.ask')]]
- [[localize('ui.auth_store.decline')]][[localize('ui.auth_store.decline')]] - [[localize('ui.auth_store.confirm')]][[localize('ui.auth_store.confirm')]]
diff --git a/src/dialogs/more-info/controls/more-info-alarm_control_panel.js b/src/dialogs/more-info/controls/more-info-alarm_control_panel.js index 5f1d186474..900b1dc1d4 100644 --- a/src/dialogs/more-info/controls/more-info-alarm_control_panel.js +++ b/src/dialogs/more-info/controls/more-info-alarm_control_panel.js @@ -1,5 +1,5 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -27,15 +27,14 @@ class MoreInfoAlarmControlPanel extends LocalizeMixin( display: flex; flex-direction: column; } - .pad paper-button { + .pad mwc-button { width: 80px; } - .actions paper-button { + .actions mwc-button { min-width: 160px; margin-bottom: 16px; - color: var(--primary-color); } - paper-button.disarm { + mwc-button.disarm { color: var(--google-red-500); } @@ -51,87 +50,87 @@ class MoreInfoAlarmControlPanel extends LocalizeMixin( @@ -139,7 +138,7 @@ class MoreInfoAlarmControlPanel extends LocalizeMixin(
`; diff --git a/src/dialogs/more-info/controls/more-info-automation.js b/src/dialogs/more-info/controls/more-info-automation.js index d65471f87d..d766184ee1 100644 --- a/src/dialogs/more-info/controls/more-info-automation.js +++ b/src/dialogs/more-info/controls/more-info-automation.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -10,10 +10,6 @@ class MoreInfoAutomation extends LocalizeMixin(PolymerElement) { static get template() { return html` - -
-
[[title]]
-
-

[[error]]

- go back -
-
- `; - } - - static get properties() { - return { - title: { - type: String, - value: "Home Assistant", - }, - - error: { - type: String, - value: "Oops! It looks like something went wrong.", - }, - }; - } - - backTapped() { - history.back(); - } -} - -customElements.define("hass-error-screen", HassErrorScreen); diff --git a/src/layouts/hass-error-screen.ts b/src/layouts/hass-error-screen.ts new file mode 100644 index 0000000000..ac382d2b37 --- /dev/null +++ b/src/layouts/hass-error-screen.ts @@ -0,0 +1,54 @@ +import { + LitElement, + CSSResultArray, + css, + TemplateResult, + html, + property, + customElement, +} from "lit-element"; +import "@material/mwc-button"; +import "./hass-subpage"; + +@customElement("hass-error-screen") +class HassErrorScreen extends LitElement { + @property() + public error?: string; + + protected render(): TemplateResult | void { + return html` + +
+

${this.error}

+ + go back + +
+
+ `; + } + + private _backTapped(): void { + history.back(); + } + + static get styles(): CSSResultArray { + return [ + css` + .content { + height: calc(100% - 64px); + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hass-error-screen": HassErrorScreen; + } +} diff --git a/src/layouts/hass-loading-screen.js b/src/layouts/hass-loading-screen.js deleted file mode 100644 index d97813833b..0000000000 --- a/src/layouts/hass-loading-screen.js +++ /dev/null @@ -1,57 +0,0 @@ -import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import "@polymer/paper-spinner/paper-spinner-lite"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../components/ha-menu-button"; - -class HassLoadingScreen extends PolymerElement { - static get template() { - return html` - - -
- - -
[[title]]
-
-
- -
-
- `; - } - - static get properties() { - return { - narrow: { - type: Boolean, - value: false, - }, - - showMenu: { - type: Boolean, - value: false, - }, - - title: { - type: String, - value: "", - }, - }; - } -} - -customElements.define("hass-loading-screen", HassLoadingScreen); diff --git a/src/layouts/hass-loading-screen.ts b/src/layouts/hass-loading-screen.ts new file mode 100644 index 0000000000..f67d376e1f --- /dev/null +++ b/src/layouts/hass-loading-screen.ts @@ -0,0 +1,56 @@ +import "@polymer/app-layout/app-toolbar/app-toolbar"; +import "@polymer/paper-spinner/paper-spinner-lite"; +import { + LitElement, + TemplateResult, + html, + property, + CSSResultArray, + css, + customElement, +} from "lit-element"; +import "../components/ha-menu-button"; +import { haStyle } from "../resources/styles"; + +@customElement("hass-loading-screen") +class HassLoadingScreen extends LitElement { + @property({ type: Boolean }) + public narrow?: boolean; + + @property({ type: Boolean }) + public showMenu?: boolean; + + protected render(): TemplateResult | void { + return html` + + + +
+ +
+ `; + } + + static get styles(): CSSResultArray { + return [ + haStyle, + css` + .content { + height: calc(100% - 64px); + display: flex; + align-items: center; + justify-content: center; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hass-loading-screen": HassLoadingScreen; + } +} diff --git a/src/layouts/hass-subpage.ts b/src/layouts/hass-subpage.ts new file mode 100644 index 0000000000..8895df0e74 --- /dev/null +++ b/src/layouts/hass-subpage.ts @@ -0,0 +1,52 @@ +import "@polymer/app-layout/app-header-layout/app-header-layout"; +import "@polymer/app-layout/app-header/app-header"; +import "@polymer/app-layout/app-toolbar/app-toolbar"; +import "@polymer/paper-icon-button/paper-icon-button"; +import { + LitElement, + property, + TemplateResult, + html, + customElement, + CSSResult, +} from "lit-element"; +import { haStyle } from "../resources/styles"; + +@customElement("hass-subpage") +class HassSubpage extends LitElement { + @property() + public header?: string; + + protected render(): TemplateResult | void { + return html` + + + + +
${this.header}
+ +
+
+ + +
+ `; + } + + private _backTapped(): void { + history.back(); + } + + static get styles(): CSSResult { + return haStyle; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hass-subpage": HassSubpage; + } +} diff --git a/src/layouts/partial-panel-resolver.ts b/src/layouts/partial-panel-resolver.ts index db43495ebb..3503c79a2c 100644 --- a/src/layouts/partial-panel-resolver.ts +++ b/src/layouts/partial-panel-resolver.ts @@ -1,6 +1,7 @@ import { LitElement, html, PropertyValues, property } from "lit-element"; import "./hass-loading-screen"; +import "./hass-error-screen"; import { HomeAssistant, Panel, PanelElement, Route } from "../types"; // Cache of panel loading promises. @@ -122,11 +123,10 @@ class PartialPanelResolver extends LitElement { if (this._error) { return html` + > `; } @@ -144,13 +144,6 @@ class PartialPanelResolver extends LitElement { `; } - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - // Load it before it's needed, because it will be shown if user is offline - // and a panel has to be loaded. - import(/* webpackChunkName: "hass-error-screen" */ "./hass-error-screen"); - } - protected updated(changedProps: PropertyValues) { super.updated(changedProps); if (!this.hass) { @@ -214,6 +207,7 @@ class PartialPanelResolver extends LitElement { this._cache[panel.component_name] = this._panelEl; } + this._error = false; this._updatePanel(); }, (err) => { diff --git a/src/onboarding/ha-onboarding.js b/src/onboarding/ha-onboarding.js index ec9d8b2149..c2cd056a55 100644 --- a/src/onboarding/ha-onboarding.js +++ b/src/onboarding/ha-onboarding.js @@ -1,7 +1,7 @@ import "@polymer/polymer/lib/elements/dom-if"; import "@polymer/polymer/lib/elements/dom-repeat"; import "@polymer/paper-input/paper-input"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; import { localizeLiteMixin } from "../mixins/localize-lite-mixin"; @@ -64,9 +64,9 @@ class HaOnboarding extends localizeLiteMixin(PolymerElement) {
diff --git a/src/panels/config/area_registry/dialog-area-registry-detail.ts b/src/panels/config/area_registry/dialog-area-registry-detail.ts index bf8e0d8425..4fd01bf688 100644 --- a/src/panels/config/area_registry/dialog-area-registry-detail.ts +++ b/src/panels/config/area_registry/dialog-area-registry-detail.ts @@ -12,7 +12,7 @@ import "@polymer/paper-input/paper-input"; import { AreaRegistryDetailDialogParams } from "./show-dialog-area-registry-detail"; import { PolymerChangedEvent } from "../../../polymer-types"; -import { haStyleDialog } from "../../../resources/ha-style"; +import { haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import { AreaRegistryEntryMutableParams } from "../../../data/area_registry"; @@ -51,7 +51,13 @@ class DialogAreaDetail extends LitElement { opened @opened-changed="${this._openedChanged}" > -

${this._params.entry ? this._params.entry.name : "New Area"}

+

+ ${this._params.entry + ? this._params.entry.name + : this.hass.localize( + "ui.panel.config.area_registry.editor.default_name" + )} +

${this._error ? html` @@ -62,7 +68,7 @@ class DialogAreaDetail extends LitElement { @@ -71,21 +77,29 @@ class DialogAreaDetail extends LitElement {
${this._params.entry ? html` - - DELETE - + ${this.hass.localize( + "ui.panel.config.area_registry.editor.delete" + )} + ` : html``} - - ${this._params.entry ? "UPDATE" : "CREATE"} - + ${this._params.entry + ? this.hass.localize( + "ui.panel.config.area_registry.editor.update" + ) + : this.hass.localize( + "ui.panel.config.area_registry.editor.create" + )} +
`; @@ -142,13 +156,7 @@ class DialogAreaDetail extends LitElement { .form { padding-bottom: 24px; } - paper-button { - font-weight: 500; - } - paper-button.danger { - font-weight: 500; - color: var(--google-red-500); - margin-left: -12px; + mwc-button.warning { margin-right: auto; } .error { diff --git a/src/panels/config/area_registry/ha-config-area-registry.ts b/src/panels/config/area_registry/ha-config-area-registry.ts index 8fe412539e..dbca7d6ba9 100644 --- a/src/panels/config/area_registry/ha-config-area-registry.ts +++ b/src/panels/config/area_registry/ha-config-area-registry.ts @@ -50,7 +50,9 @@ class HaConfigAreaRegistry extends LitElement { return html` - Area Registry + + ${this.hass.localize("ui.panel.config.area_registry.picker.header")} + Areas are used to organize where devices are. This information will be used throughout Home Assistant to help you in organizing your @@ -74,10 +76,14 @@ class HaConfigAreaRegistry extends LitElement { ${this._items.length === 0 ? html`
- Looks like you have no areas yet! - - CREATE AREA + ${this.hass.localize( + "ui.panel.config.area_registry.picker.no_areas" + )} + + ${this.hass.localize( + "ui.panel.config.area_registry.picker.create_area" + )} +
` : html``} diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index aca9d44726..b2ad95173d 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -11,6 +11,7 @@ import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-fab/paper-fab"; +import { classMap } from "lit-html/directives/class-map"; import { h, render } from "preact"; @@ -21,10 +22,11 @@ import Automation from "../js/automation"; import unmountPreact from "../../../common/preact/unmount"; import computeStateName from "../../../common/entity/compute_state_name"; -import { haStyle } from "../../../resources/ha-style"; +import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import { AutomationEntity, AutomationConfig } from "../../../data/automation"; import { navigate } from "../../../common/navigate"; +import { computeRTL } from "../../../common/util/compute_rtl"; function AutomationEditor(mountEl, props, mergeEl) { return render(h(Automation, props), mountEl, mergeEl); @@ -92,7 +94,12 @@ class HaAutomationEditor extends LitElement {
${this._errors}
` : ""} -
+
VIEW DOCUMENTATIONVIEW DOCUMENTATION - CLOSE + CLOSE `; @@ -129,10 +129,6 @@ export class CloudWebhookManageDialog extends LitElement { button.link { color: var(--primary-color); } - paper-button { - color: var(--primary-color); - font-weight: 500; - } `, ]; } diff --git a/src/panels/config/cloud/cloud-webhooks.ts b/src/panels/config/cloud/cloud-webhooks.ts index 910fdeab7a..a3edd199d2 100644 --- a/src/panels/config/cloud/cloud-webhooks.ts +++ b/src/panels/config/cloud/cloud-webhooks.ts @@ -122,8 +122,8 @@ export class CloudWebhooks extends LitElement { ` : this._cloudHooks![entry.webhook_id] ? html` - ManageManage ` : html` @@ -226,10 +226,6 @@ export class CloudWebhooks extends LitElement { flex-direction: column; justify-content: center; } - paper-button { - font-weight: 500; - color: var(--primary-color); - } .footer { padding: 16px; } diff --git a/src/panels/config/cloud/ha-config-cloud-account.js b/src/panels/config/cloud/ha-config-cloud-account.js index e47e26aa14..38a4e1fcc9 100644 --- a/src/panels/config/cloud/ha-config-cloud-account.js +++ b/src/panels/config/cloud/ha-config-cloud-account.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-toggle-button/paper-toggle-button"; @@ -39,6 +39,7 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { } .content { padding-bottom: 24px; + direction: ltr; } paper-card { display: block; @@ -47,7 +48,7 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { display: flex; padding: 0 16px; } - paper-button { + mwc-button { align-self: center; } .soon { @@ -65,10 +66,6 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { text-transform: capitalize; padding: 16px; } - paper-button { - color: var(--primary-color); - font-weight: 500; - }
@@ -99,10 +96,10 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
Manage AccountManage Account - Sign outSign out
diff --git a/src/panels/config/cloud/ha-config-cloud-forgot-password.js b/src/panels/config/cloud/ha-config-cloud-forgot-password.js index 847ebfcb9b..1e8668c756 100644 --- a/src/panels/config/cloud/ha-config-cloud-forgot-password.js +++ b/src/panels/config/cloud/ha-config-cloud-forgot-password.js @@ -17,6 +17,7 @@ class HaConfigCloudForgotPassword extends EventsMixin(PolymerElement) { @@ -55,12 +58,13 @@ class HaUserEditor extends EventsMixin(
- [[localize('ui.panel.config.users.editor.delete_user')]] - + diff --git a/src/panels/config/zha/functions.ts b/src/panels/config/zha/functions.ts new file mode 100644 index 0000000000..e5475280ea --- /dev/null +++ b/src/panels/config/zha/functions.ts @@ -0,0 +1,7 @@ +export const formatAsPaddedHex = (value: string | number): string => { + let hex = value; + if (typeof value === "string") { + hex = parseInt(value, 16); + } + return "0x" + hex.toString(16).padStart(4, "0"); +}; diff --git a/src/panels/config/zha/ha-config-zha.ts b/src/panels/config/zha/ha-config-zha.ts index 25b61a1f2a..ef9c06b59e 100755 --- a/src/panels/config/zha/ha-config-zha.ts +++ b/src/panels/config/zha/ha-config-zha.ts @@ -13,13 +13,9 @@ import { HASSDomEvent } from "../../../common/dom/fire_event"; import { Cluster } from "../../../data/zha"; import "../../../layouts/ha-app-layout"; import "../../../components/ha-paper-icon-button-arrow-prev"; -import { haStyle } from "../../../resources/ha-style"; +import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; -import { - ZHAClusterSelectedParams, - ZHAEntitySelectedParams, - ZHANodeSelectedParams, -} from "./types"; +import { ZHAClusterSelectedParams, ZHANodeSelectedParams } from "./types"; import "./zha-cluster-attributes"; import "./zha-cluster-commands"; import "./zha-network"; @@ -30,14 +26,12 @@ export class HaConfigZha extends LitElement { public isWide?: boolean; private _selectedNode?: HassEntity; private _selectedCluster?: Cluster; - private _selectedEntity?: HassEntity; static get properties(): PropertyDeclarations { return { hass: {}, isWide: {}, _selectedCluster: {}, - _selectedEntity: {}, _selectedNode: {}, }; } @@ -64,7 +58,6 @@ export class HaConfigZha extends LitElement { .hass="${this.hass}" @zha-cluster-selected="${this._onClusterSelected}" @zha-node-selected="${this._onNodeSelected}" - @zha-entity-selected="${this._onEntitySelected}" > ${this._selectedCluster ? html` @@ -72,7 +65,6 @@ export class HaConfigZha extends LitElement { .isWide="${this.isWide}" .hass="${this.hass}" .selectedNode="${this._selectedNode}" - .selectedEntity="${this._selectedEntity}" .selectedCluster="${this._selectedCluster}" > @@ -80,7 +72,6 @@ export class HaConfigZha extends LitElement { .isWide="${this.isWide}" .hass="${this.hass}" .selectedNode="${this._selectedNode}" - .selectedEntity="${this._selectedEntity}" .selectedCluster="${this._selectedCluster}" > ` @@ -100,13 +91,6 @@ export class HaConfigZha extends LitElement { ): void { this._selectedNode = selectedNodeEvent.detail.node; this._selectedCluster = undefined; - this._selectedEntity = undefined; - } - - private _onEntitySelected( - selectedEntityEvent: HASSDomEvent - ): void { - this._selectedEntity = selectedEntityEvent.detail.entity; } static get styles(): CSSResult[] { diff --git a/src/panels/config/zha/types.ts b/src/panels/config/zha/types.ts index 23bc9f74d7..1f006964d7 100644 --- a/src/panels/config/zha/types.ts +++ b/src/panels/config/zha/types.ts @@ -1,4 +1,3 @@ -import { HassEntity } from "home-assistant-js-websocket"; import { ZHADeviceEntity, Cluster } from "../../../data/zha"; export interface PickerTarget extends EventTarget { @@ -17,7 +16,8 @@ export interface ChangeEvent { } export interface SetAttributeServiceData { - entity_id: string; + ieee: string; + endpoint_id: number; cluster_id: number; cluster_type: string; attribute: number; @@ -26,17 +26,14 @@ export interface SetAttributeServiceData { } export interface IssueCommandServiceData { - entity_id: string; + ieee: string; + endpoint_id: number; cluster_id: number; cluster_type: string; command: number; command_type: string; } -export interface ZHAEntitySelectedParams { - entity: HassEntity; -} - export interface ZHANodeSelectedParams { node: ZHADeviceEntity; } diff --git a/src/panels/config/zha/zha-cluster-attributes.ts b/src/panels/config/zha/zha-cluster-attributes.ts index d19354cdcd..c59126cbf2 100644 --- a/src/panels/config/zha/zha-cluster-attributes.ts +++ b/src/panels/config/zha/zha-cluster-attributes.ts @@ -7,10 +7,9 @@ import { CSSResult, css, } from "lit-element"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-icon-button/paper-icon-button"; -import { HassEntity } from "home-assistant-js-websocket"; import "../../../components/buttons/ha-call-service-button"; import "../../../components/ha-service-description"; import { @@ -19,9 +18,9 @@ import { fetchAttributesForCluster, ReadAttributeServiceData, readAttributeValue, - ZHADeviceEntity, + ZHADevice, } from "../../../data/zha"; -import { haStyle } from "../../../resources/ha-style"; +import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import "../ha-config-section"; import { @@ -29,13 +28,13 @@ import { ItemSelectedEvent, SetAttributeServiceData, } from "./types"; +import { formatAsPaddedHex } from "./functions"; export class ZHAClusterAttributes extends LitElement { public hass?: HomeAssistant; public isWide?: boolean; public showHelp: boolean; - public selectedNode?: HassEntity; - public selectedEntity?: ZHADeviceEntity; + public selectedNode?: ZHADevice; public selectedCluster?: Cluster; private _attributes: Attribute[]; private _selectedAttributeIndex: number; @@ -57,7 +56,6 @@ export class ZHAClusterAttributes extends LitElement { isWide: {}, showHelp: {}, selectedNode: {}, - selectedEntity: {}, selectedCluster: {}, _attributes: {}, _selectedAttributeIndex: {}, @@ -105,7 +103,10 @@ export class ZHAClusterAttributes extends LitElement { ${this._attributes.map( (entry) => html` ${entry.name + " (id: " + entry.id + ")"}${entry.name + + " (id: " + + formatAsPaddedHex(entry.id) + + ")"} ` )} @@ -148,8 +149,8 @@ export class ZHAClusterAttributes extends LitElement { >
- Get Zigbee AttributeGet Zigbee Attribute { - if (this.selectedEntity && this.selectedCluster && this.hass) { + if (this.selectedNode && this.selectedCluster && this.hass) { this._attributes = await fetchAttributesForCluster( this.hass, - this.selectedEntity!.entity_id, - this.selectedEntity!.device_info!.identifiers[0][1], + this.selectedNode!.ieee, + this.selectedCluster!.endpoint_id, this.selectedCluster!.id, this.selectedCluster!.type ); + this._attributes.sort((a, b) => { + return a.name.localeCompare(b.name); + }); } } private _computeReadAttributeServiceData(): | ReadAttributeServiceData | undefined { - if (!this.selectedEntity || !this.selectedCluster || !this.selectedNode) { + if (!this.selectedCluster || !this.selectedNode) { return; } return { - entity_id: this.selectedEntity!.entity_id, + ieee: this.selectedNode!.ieee, + endpoint_id: this.selectedCluster!.endpoint_id, cluster_id: this.selectedCluster!.id, cluster_type: this.selectedCluster!.type, attribute: this._attributes[this._selectedAttributeIndex].id, manufacturer: this._manufacturerCodeOverride ? parseInt(this._manufacturerCodeOverride as string, 10) - : this.selectedNode!.attributes.manufacturer_code, + : this.selectedNode!.manufacturer_code, }; } private _computeSetAttributeServiceData(): | SetAttributeServiceData | undefined { - if (!this.selectedEntity || !this.selectedCluster || !this.selectedNode) { + if (!this.selectedCluster || !this.selectedNode) { return; } return { - entity_id: this.selectedEntity!.entity_id, + ieee: this.selectedNode!.ieee, + endpoint_id: this.selectedCluster!.endpoint_id, cluster_id: this.selectedCluster!.id, cluster_type: this.selectedCluster!.type, attribute: this._attributes[this._selectedAttributeIndex].id, value: this._attributeValue, manufacturer: this._manufacturerCodeOverride ? parseInt(this._manufacturerCodeOverride as string, 10) - : this.selectedNode!.attributes.manufacturer_code, + : this.selectedNode!.manufacturer_code, }; } @@ -306,8 +312,7 @@ export class ZHAClusterAttributes extends LitElement { [hidden] { display: none; } - - `, + `, ]; } } diff --git a/src/panels/config/zha/zha-cluster-commands.ts b/src/panels/config/zha/zha-cluster-commands.ts index 398a7ff3d6..28a68af9ab 100644 --- a/src/panels/config/zha/zha-cluster-commands.ts +++ b/src/panels/config/zha/zha-cluster-commands.ts @@ -8,16 +8,15 @@ import { css, } from "lit-element"; import "@polymer/paper-card/paper-card"; -import { HassEntity } from "home-assistant-js-websocket"; import "../../../components/buttons/ha-call-service-button"; import "../../../components/ha-service-description"; import { Cluster, Command, fetchCommandsForCluster, - ZHADeviceEntity, + ZHADevice, } from "../../../data/zha"; -import { haStyle } from "../../../resources/ha-style"; +import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import "../ha-config-section"; import { @@ -25,12 +24,12 @@ import { IssueCommandServiceData, ItemSelectedEvent, } from "./types"; +import { formatAsPaddedHex } from "./functions"; export class ZHAClusterCommands extends LitElement { public hass?: HomeAssistant; public isWide?: boolean; - public selectedNode?: HassEntity; - public selectedEntity?: ZHADeviceEntity; + public selectedNode?: ZHADevice; public selectedCluster?: Cluster; private _showHelp: boolean; private _commands: Command[]; @@ -50,7 +49,6 @@ export class ZHAClusterCommands extends LitElement { hass: {}, isWide: {}, selectedNode: {}, - selectedEntity: {}, selectedCluster: {}, _showHelp: {}, _commands: {}, @@ -97,7 +95,10 @@ export class ZHAClusterCommands extends LitElement { ${this._commands.map( (entry) => html` ${entry.name + " (id: " + entry.id + ")"}${entry.name + + " (id: " + + formatAsPaddedHex(entry.id) + + ")"} ` )} @@ -146,25 +147,29 @@ export class ZHAClusterCommands extends LitElement { } private async _fetchCommandsForCluster(): Promise { - if (this.selectedEntity && this.selectedCluster && this.hass) { + if (this.selectedNode && this.selectedCluster && this.hass) { this._commands = await fetchCommandsForCluster( this.hass, - this.selectedEntity!.entity_id, - this.selectedEntity!.device_info!.identifiers[0][1], + this.selectedNode!.ieee, + this.selectedCluster!.endpoint_id, this.selectedCluster!.id, this.selectedCluster!.type ); + this._commands.sort((a, b) => { + return a.name.localeCompare(b.name); + }); } } private _computeIssueClusterCommandServiceData(): | IssueCommandServiceData | undefined { - if (!this.selectedEntity || !this.selectedCluster) { + if (!this.selectedNode || !this.selectedCluster) { return; } return { - entity_id: this.selectedEntity!.entity_id, + ieee: this.selectedNode!.ieee, + endpoint_id: this.selectedCluster!.endpoint_id, cluster_id: this.selectedCluster!.id, cluster_type: this.selectedCluster!.type, command: this._commands[this._selectedCommandIndex].id, @@ -257,8 +262,7 @@ export class ZHAClusterCommands extends LitElement { [hidden] { display: none; } - - `, + `, ]; } } diff --git a/src/panels/config/zha/zha-clusters.ts b/src/panels/config/zha/zha-clusters.ts index d580cc49c6..bbabf3e2fa 100644 --- a/src/panels/config/zha/zha-clusters.ts +++ b/src/panels/config/zha/zha-clusters.ts @@ -11,15 +11,12 @@ 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, - ZHADeviceEntity, -} from "../../../data/zha"; -import { haStyle } from "../../../resources/ha-style"; +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"; declare global { // for fire event @@ -31,14 +28,16 @@ declare global { } const computeClusterKey = (cluster: Cluster): string => { - return `${cluster.name} (id: ${cluster.id}, type: ${cluster.type})`; + return `${cluster.name} (Endpoint id: ${ + cluster.endpoint_id + }, Id: ${formatAsPaddedHex(cluster.id)}, Type: ${cluster.type})`; }; export class ZHAClusters extends LitElement { public hass?: HomeAssistant; public isWide?: boolean; public showHelp: boolean; - public selectedEntity?: ZHADeviceEntity; + public selectedDevice?: ZHADevice; private _selectedClusterIndex: number; private _clusters: Cluster[]; @@ -54,14 +53,14 @@ export class ZHAClusters extends LitElement { hass: {}, isWide: {}, showHelp: {}, - selectedEntity: {}, + selectedDevice: {}, _selectedClusterIndex: {}, _clusters: {}, }; } protected updated(changedProperties: PropertyValues): void { - if (changedProperties.has("selectedEntity")) { + if (changedProperties.has("selectedDevice")) { this._clusters = []; this._selectedClusterIndex = -1; fireEvent(this, "zha-cluster-selected", { @@ -103,9 +102,11 @@ export class ZHAClusters extends LitElement { if (this.hass) { this._clusters = await fetchClustersForZhaNode( this.hass, - this.selectedEntity!.entity_id, - this.selectedEntity!.device_info!.identifiers[0][1] + this.selectedDevice!.ieee ); + this._clusters.sort((a, b) => { + return a.name.localeCompare(b.name); + }); } } diff --git a/src/panels/config/zha/zha-device-card.ts b/src/panels/config/zha/zha-device-card.ts new file mode 100644 index 0000000000..d68d724ecb --- /dev/null +++ b/src/panels/config/zha/zha-device-card.ts @@ -0,0 +1,118 @@ +import { + html, + LitElement, + property, + 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 { haStyle } from "../../../resources/styles"; +import { HomeAssistant } from "../../../types"; + +import "../../../components/entity/state-badge"; +import { ZHADevice } from "../../../data/zha"; + +class ZHADeviceCard extends LitElement { + @property() public hass?: HomeAssistant; + @property() public narrow?: boolean; + @property() public device?: ZHADevice; + + protected render(): TemplateResult | void { + return html` + +
+
+
IEEE:
+
${this.device!.ieee}
+
Quirk applied:
+
${this.device!.quirk_applied}
+
Quirk:
+
${this.device!.quirk_class}
+
+
+ +
+ ${this.device!.entities.map( + (entity) => html` + + + +
${entity.name}
+
${entity.entity_id}
+
+
+ ` + )} +
+
+ `; + } + + private _openMoreInfo(ev: MouseEvent): void { + fireEvent(this, "hass-more-info", { + entityId: (ev.currentTarget as any).entity.entity_id, + }); + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + :host(:not([narrow])) .device-entities { + max-height: 225px; + overflow: auto; + } + paper-card { + flex: 1 0 100%; + padding-bottom: 10px; + min-width: 0; + } + .device { + width: 30%; + } + .label { + font-weight: bold; + } + .info { + color: var(--secondary-text-color); + font-weight: bold; + } + dl dt { + float: left; + width: 100px; + text-align: left; + } + dt dd { + margin-left: 10px; + text-align: left; + } + paper-icon-item { + cursor: pointer; + padding-top: 4px; + padding-bottom: 4px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-device-card": ZHADeviceCard; + } +} + +customElements.define("zha-device-card", ZHADeviceCard); diff --git a/src/panels/config/zha/zha-entities.ts b/src/panels/config/zha/zha-entities.ts deleted file mode 100644 index 9b6f373f07..0000000000 --- a/src/panels/config/zha/zha-entities.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { - html, - LitElement, - PropertyDeclarations, - PropertyValues, - TemplateResult, - CSSResult, - css, -} from "lit-element"; -import "@polymer/paper-button/paper-button"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; -import { HassEntity } from "home-assistant-js-websocket"; -import { fireEvent } from "../../../common/dom/fire_event"; -import { fetchEntitiesForZhaNode } from "../../../data/zha"; -import { haStyle } from "../../../resources/ha-style"; -import { HomeAssistant } from "../../../types"; -import { ItemSelectedEvent } from "./types"; - -declare global { - // for fire event - interface HASSDomEvents { - "zha-entity-selected": { - entity?: HassEntity; - }; - } -} - -export class ZHAEntities extends LitElement { - public hass?: HomeAssistant; - public showHelp?: boolean; - public selectedNode?: HassEntity; - private _selectedEntityIndex: number; - private _entities: HassEntity[]; - - constructor() { - super(); - this._entities = []; - this._selectedEntityIndex = -1; - } - - static get properties(): PropertyDeclarations { - return { - hass: {}, - showHelp: {}, - selectedNode: {}, - _selectedEntityIndex: {}, - _entities: {}, - }; - } - - protected updated(changedProperties: PropertyValues): void { - if (changedProperties.has("selectedNode")) { - this._entities = []; - this._selectedEntityIndex = -1; - fireEvent(this, "zha-entity-selected", { - entity: undefined, - }); - this._fetchEntitiesForZhaNode(); - } - super.update(changedProperties); - } - - protected render(): TemplateResult | void { - return html` -
- - - ${this._entities.map( - (entry) => html` - ${entry.entity_id} - ` - )} - - -
- ${this.showHelp - ? html` -
- Select entity to view per-entity options -
- ` - : ""} - ${this._selectedEntityIndex !== -1 - ? html` -
- Entity Information -
- ` - : ""} - `; - } - - private async _fetchEntitiesForZhaNode(): Promise { - if (this.hass) { - const fetchedEntities = await fetchEntitiesForZhaNode(this.hass); - this._entities = fetchedEntities[this.selectedNode!.attributes.ieee]; - } - } - - private _selectedEntityChanged(event: ItemSelectedEvent): void { - this._selectedEntityIndex = event.target!.selected; - fireEvent(this, "zha-entity-selected", { - entity: this._entities[this._selectedEntityIndex], - }); - } - - private _showEntityInformation(): void { - fireEvent(this, "hass-more-info", { - entityId: this._entities[this._selectedEntityIndex].entity_id, - }); - } - - static get styles(): CSSResult[] { - return [ - haStyle, - css` - .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; - } - .actions { - border-top: 1px solid #e8e8e8; - padding: 5px 16px; - position: relative; - } - .actions paper-button:not([disabled]) { - color: var(--primary-color); - font-weight: 500; - } - .helpText { - color: grey; - padding: 16px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-entities": ZHAEntities; - } -} - -customElements.define("zha-entities", ZHAEntities); diff --git a/src/panels/config/zha/zha-network.ts b/src/panels/config/zha/zha-network.ts index bbd70a1629..87cf043838 100644 --- a/src/panels/config/zha/zha-network.ts +++ b/src/panels/config/zha/zha-network.ts @@ -6,12 +6,12 @@ import { CSSResult, css, } from "lit-element"; -import "@polymer/paper-button/paper-button"; +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 { haStyle } from "../../../resources/ha-style"; +import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import "../ha-config-section"; @@ -102,8 +102,7 @@ export class ZHANetwork extends LitElement { [hidden] { display: none; } - - `, + `, ]; } } diff --git a/src/panels/config/zha/zha-node.ts b/src/panels/config/zha/zha-node.ts index 2c2a680b10..0cd4e6777e 100644 --- a/src/panels/config/zha/zha-node.ts +++ b/src/panels/config/zha/zha-node.ts @@ -4,36 +4,30 @@ import { PropertyDeclarations, TemplateResult, CSSResult, + PropertyValues, css, } from "lit-element"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { HassEntity } from "home-assistant-js-websocket"; -import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event"; -import computeStateName from "../../../common/entity/compute_state_name"; -import sortByName from "../../../common/entity/states_sort_by_name"; +import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/buttons/ha-call-service-button"; import "../../../components/ha-service-description"; -import { haStyle } from "../../../resources/ha-style"; +import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import "../ha-config-section"; -import { - ItemSelectedEvent, - NodeServiceData, - ZHAEntitySelectedParams, -} from "./types"; +import { ItemSelectedEvent, NodeServiceData } from "./types"; import "./zha-clusters"; -import "./zha-entities"; -import { reconfigureNode } from "../../../data/zha"; +import "./zha-device-card"; +import { reconfigureNode, fetchDevices, ZHADevice } from "../../../data/zha"; declare global { // for fire event interface HASSDomEvents { "zha-node-selected": { - node?: HassEntity; + node?: ZHADevice; }; } } @@ -43,10 +37,9 @@ export class ZHANode extends LitElement { public isWide?: boolean; private _showHelp: boolean; private _selectedNodeIndex: number; - private _selectedNode?: HassEntity; - private _selectedEntity?: HassEntity; + private _selectedNode?: ZHADevice; private _serviceData?: {}; - private _nodes: HassEntity[]; + private _nodes: ZHADevice[]; constructor() { super(); @@ -62,13 +55,31 @@ export class ZHANode extends LitElement { _showHelp: {}, _selectedNodeIndex: {}, _selectedNode: {}, + _entities: {}, _serviceData: {}, - _selectedEntity: {}, + _nodes: {}, }; } + 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(); + } + } + protected render(): TemplateResult | void { - this._nodes = this._computeNodes(this.hass); return html`
@@ -94,12 +105,11 @@ export class ZHANode extends LitElement { ${this._nodes.map( (entry) => html` - ${this._computeSelectCaption(entry)} + ${entry.name} ` )} @@ -112,9 +122,18 @@ export class ZHANode extends LitElement {
` : ""} + ${this._selectedNodeIndex !== -1 + ? html` + + ` + : ""} ${this._selectedNodeIndex !== -1 ? this._renderNodeActions() : ""} - ${this._selectedNodeIndex !== -1 ? this._renderEntities() : ""} - ${this._selectedEntity ? this._renderClusters() : ""} + ${this._selectedNode ? this._renderClusters() : ""}
`; @@ -123,11 +142,8 @@ export class ZHANode extends LitElement { private _renderNodeActions(): TemplateResult { return html`
- Node Information - Reconfigure NodeReconfigure Node ${this._showHelp ? html` @@ -158,22 +174,11 @@ export class ZHANode extends LitElement { `; } - private _renderEntities(): TemplateResult { - return html` - - `; - } - private _renderClusters(): TemplateResult { return html` `; @@ -186,50 +191,26 @@ export class ZHANode extends LitElement { private _selectedNodeChanged(event: ItemSelectedEvent): void { this._selectedNodeIndex = event!.target!.selected; this._selectedNode = this._nodes[this._selectedNodeIndex]; - this._selectedEntity = undefined; fireEvent(this, "zha-node-selected", { node: this._selectedNode }); this._serviceData = this._computeNodeServiceData(); } private async _onReconfigureNodeClick(): Promise { if (this.hass) { - await reconfigureNode(this.hass, this._selectedNode!.attributes.ieee); + await reconfigureNode(this.hass, this._selectedNode!.ieee); } } - private _showNodeInformation(): void { - fireEvent(this, "hass-more-info", { - entityId: this._selectedNode!.entity_id, - }); - } - private _computeNodeServiceData(): NodeServiceData { return { - ieee_address: this._selectedNode!.attributes.ieee, + ieee_address: this._selectedNode!.ieee, }; } - private _computeSelectCaption(stateObj: HassEntity): string { - return ( - computeStateName(stateObj) + " (Node:" + stateObj.attributes.ieee + ")" - ); - } - - private _computeNodes(hass?: HomeAssistant): HassEntity[] { - if (hass) { - return Object.keys(hass.states) - .map((key) => hass.states[key]) - .filter((ent) => ent.entity_id.match("zha[.]")) - .sort(sortByName); - } else { - return []; - } - } - - private _onEntitySelected( - entitySelectedEvent: HASSDomEvent - ): void { - this._selectedEntity = entitySelectedEvent.detail.entity; + private async _fetchDevices() { + this._nodes = (await fetchDevices(this.hass!)).sort((a, b) => { + return a.name.localeCompare(b.name); + }); } static get styles(): CSSResult[] { @@ -287,6 +268,17 @@ export class ZHANode extends LitElement { padding-bottom: 10px; } + .card { + box-sizing: border-box; + display: flex; + flex: 1 0 300px; + min-width: 0; + max-width: 600px; + padding-left: 28px; + padding-right: 28px; + padding-bottom: 10px; + } + ha-service-description { display: block; color: grey; diff --git a/src/panels/config/zwave/ha-config-zwave.js b/src/panels/config/zwave/ha-config-zwave.js index 8a03b610ae..81f536dfb4 100644 --- a/src/panels/config/zwave/ha-config-zwave.js +++ b/src/panels/config/zwave/ha-config-zwave.js @@ -236,8 +236,8 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) { hidden$="[[!showHelp]]" > - Node InformationNode Information
@@ -277,8 +277,8 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) { hidden$="[[!showHelp]]" > - Entity InformationEntity Information
diff --git a/src/panels/config/zwave/zwave-log.js b/src/panels/config/zwave/zwave-log.js index 3c3269e31c..a0524d08a9 100644 --- a/src/panels/config/zwave/zwave-log.js +++ b/src/panels/config/zwave/zwave-log.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-input/paper-input"; @@ -42,8 +42,8 @@ class OzwLog extends EventsMixin(PolymerElement) {
- Load - Tail + Load + Tail `; diff --git a/src/panels/dev-event/ha-panel-dev-event.js b/src/panels/dev-event/ha-panel-dev-event.js index 9fddd75adf..8ad0511d49 100644 --- a/src/panels/dev-event/ha-panel-dev-event.js +++ b/src/panels/dev-event/ha-panel-dev-event.js @@ -2,7 +2,7 @@ import "@polymer/app-layout/app-header-layout/app-header-layout"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; import { html } from "@polymer/polymer/lib/utils/html-tag"; @@ -68,9 +68,7 @@ class HaPanelDevEvent extends EventsMixin(PolymerElement) { label="Event Data (JSON, optional)" value="{{eventData}}" > - Fire Event + Fire Event
diff --git a/src/panels/dev-info/dialog-system-log-detail.ts b/src/panels/dev-info/dialog-system-log-detail.ts index 10dcfdfff8..52666522ed 100644 --- a/src/panels/dev-info/dialog-system-log-detail.ts +++ b/src/panels/dev-info/dialog-system-log-detail.ts @@ -11,7 +11,7 @@ import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import { SystemLogDetailDialogParams } from "./show-dialog-system-log-detail"; import { PolymerChangedEvent } from "../../polymer-types"; -import { haStyleDialog } from "../../resources/ha-style"; +import { haStyleDialog } from "../../resources/styles"; class DialogSystemLogDetail extends LitElement { private _params?: SystemLogDetailDialogParams; diff --git a/src/panels/dev-info/error-log-card.ts b/src/panels/dev-info/error-log-card.ts index 88e3208c7d..46b4274492 100644 --- a/src/panels/dev-info/error-log-card.ts +++ b/src/panels/dev-info/error-log-card.ts @@ -7,7 +7,7 @@ import { TemplateResult, } from "lit-element"; import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import { HomeAssistant } from "../../types"; import { fetchErrorLog } from "../../data/error_log"; @@ -34,9 +34,9 @@ class ErrorLogCard extends LitElement { > ` : html` - + Load Full Home Assistant Log - + `}

${this._errorLog}
diff --git a/src/panels/dev-info/ha-panel-dev-info.ts b/src/panels/dev-info/ha-panel-dev-info.ts index b19a134cf5..200bf3baba 100644 --- a/src/panels/dev-info/ha-panel-dev-info.ts +++ b/src/panels/dev-info/ha-panel-dev-info.ts @@ -12,7 +12,7 @@ import "@polymer/app-layout/app-toolbar/app-toolbar"; import "../../components/ha-menu-button"; import { HomeAssistant } from "../../types"; -import { haStyle } from "../../resources/ha-style"; +import { haStyle } from "../../resources/styles"; import "./system-log-card"; import "./error-log-card"; @@ -138,9 +138,9 @@ class HaPanelDevInfo extends LitElement {

${nonDefaultLinkText}
- + ${defaultPageText} - +

diff --git a/src/panels/dev-info/system-health-card.ts b/src/panels/dev-info/system-health-card.ts index 753a2aa851..fbe78da9b6 100644 --- a/src/panels/dev-info/system-health-card.ts +++ b/src/panels/dev-info/system-health-card.ts @@ -51,7 +51,9 @@ class SystemHealthCard extends LitElement { if (!this._info) { sections.push( html` - +
+ +
` ); } else { @@ -120,6 +122,12 @@ class SystemHealthCard extends LitElement { td:first-child { width: 33%; } + + .loading-container { + display: flex; + align-items: center; + justify-content: center; + } `; } } diff --git a/src/panels/dev-info/system-log-card.ts b/src/panels/dev-info/system-log-card.ts index 11104a5dc5..59c11ca61c 100644 --- a/src/panels/dev-info/system-log-card.ts +++ b/src/panels/dev-info/system-log-card.ts @@ -137,9 +137,10 @@ class SystemLogCard extends LitElement { } .loading-container { - @apply --layout-vertical; - @apply --layout-center-center; height: 100px; + display: flex; + align-items: center; + justify-content: center; } `; } diff --git a/src/panels/dev-mqtt/ha-panel-dev-mqtt.js b/src/panels/dev-mqtt/ha-panel-dev-mqtt.js index 2d8647179e..7d539f1eb4 100644 --- a/src/panels/dev-mqtt/ha-panel-dev-mqtt.js +++ b/src/panels/dev-mqtt/ha-panel-dev-mqtt.js @@ -1,7 +1,7 @@ import "@polymer/app-layout/app-header-layout/app-header-layout"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; @@ -33,7 +33,7 @@ class HaPanelDevMqtt extends PolymerElement { display: block; } - paper-button { + mwc-button { background-color: white; } @@ -69,7 +69,7 @@ class HaPanelDevMqtt extends PolymerElement { >
- Publish + Publish
diff --git a/src/panels/dev-service/ha-panel-dev-service.js b/src/panels/dev-service/ha-panel-dev-service.js index f249a5de69..6505f1dc02 100644 --- a/src/panels/dev-service/ha-panel-dev-service.js +++ b/src/panels/dev-service/ha-panel-dev-service.js @@ -1,7 +1,7 @@ import "@polymer/app-layout/app-header-layout/app-header-layout"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-input/paper-textarea"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -131,11 +131,8 @@ class HaPanelDevService extends PolymerElement { autocomplete="off" spellcheck="false" > - Call ServiceCall Service diff --git a/src/panels/profile/ha-long-lived-access-tokens-card.js b/src/panels/profile/ha-long-lived-access-tokens-card.js index 3493bc20bd..3a582d993f 100644 --- a/src/panels/profile/ha-long-lived-access-tokens-card.js +++ b/src/panels/profile/ha-long-lived-access-tokens-card.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -61,9 +61,9 @@ class HaLongLivedTokens extends LocalizeMixin(EventsMixin(PolymerElement)) {
- + [[localize('ui.panel.profile.long_lived_access_tokens.create')]] - +
`; diff --git a/src/panels/profile/ha-mfa-module-setup-flow.js b/src/panels/profile/ha-mfa-module-setup-flow.js index 27f7da490e..f8feef4a72 100644 --- a/src/panels/profile/ha-mfa-module-setup-flow.js +++ b/src/panels/profile/ha-mfa-module-setup-flow.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import "@polymer/paper-dialog/paper-dialog"; import "@polymer/paper-spinner/paper-spinner"; @@ -107,13 +107,13 @@ class HaMfaModuleSetupFlow extends LocalizeMixin(EventsMixin(PolymerElement)) {
diff --git a/src/panels/profile/ha-mfa-modules-card.js b/src/panels/profile/ha-mfa-modules-card.js index 50d07606f5..f791f200ef 100644 --- a/src/panels/profile/ha-mfa-modules-card.js +++ b/src/panels/profile/ha-mfa-modules-card.js @@ -1,4 +1,4 @@ -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item"; @@ -36,9 +36,7 @@ class HaMfaModulesCard extends EventsMixin(LocalizeMixin(PolymerElement)) { max-width: 600px; margin: 16px auto; } - paper-button { - color: var(--primary-color); - font-weight: 500; + mwc-button { margin-right: -0.57em; } @@ -50,13 +48,13 @@ class HaMfaModulesCard extends EventsMixin(LocalizeMixin(PolymerElement)) {
[[module.id]]
diff --git a/src/panels/profile/ha-panel-profile.js b/src/panels/profile/ha-panel-profile.js index b07f16b943..f6672183c5 100644 --- a/src/panels/profile/ha-panel-profile.js +++ b/src/panels/profile/ha-panel-profile.js @@ -3,7 +3,7 @@ import "@polymer/app-layout/app-header/app-header"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -86,8 +86,8 @@ class HaPanelProfile extends EventsMixin(LocalizeMixin(PolymerElement)) { >
- [[localize('ui.panel.profile.logout')]][[localize('ui.panel.profile.logout')]]
diff --git a/src/resources/ha-style.ts b/src/resources/ha-style.ts index 0c7e1f45ae..85e9b17d75 100644 --- a/src/resources/ha-style.ts +++ b/src/resources/ha-style.ts @@ -1,99 +1,6 @@ import "@polymer/paper-styles/paper-styles"; import "@polymer/polymer/polymer-legacy"; -import { css } from "lit-element"; - -export const haStyle = css` - :host { - @apply --paper-font-body1; - } - - app-header-layout, - ha-app-layout { - background-color: var(--primary-background-color); - } - - app-header, - app-toolbar { - background-color: var(--primary-color); - font-weight: 400; - color: var(--text-primary-color, white); - } - - app-toolbar ha-menu-button + [main-title], - app-toolbar paper-icon-button + [main-title] { - margin-left: 24px; - } - - h1 { - @apply --paper-font-title; - } - - button.link { - background: none; - color: inherit; - border: none; - padding: 0; - font: inherit; - text-align: left; - text-decoration: underline; - cursor: pointer; - } - - .card-actions a { - text-decoration: none; - } - - .card-actions paper-button:not([disabled]), - .card-actions ha-progress-button:not([disabled]), - .card-actions ha-call-api-button:not([disabled]), - .card-actions ha-call-service-button:not([disabled]) { - color: var(--primary-color); - font-weight: 500; - } - - .card-actions paper-button.warning:not([disabled]), - .card-actions ha-call-api-button.warning:not([disabled]), - .card-actions ha-call-service-button.warning:not([disabled]) { - color: var(--google-red-500); - } - - .card-actions paper-button[primary] { - background-color: var(--primary-color); - color: var(--text-primary-color); - } -`; - -export const haStyleDialog = css` - /* prevent clipping of positioned elements */ - paper-dialog-scrollable { - --paper-dialog-scrollable: { - -webkit-overflow-scrolling: auto; - } - } - - /* force smooth scrolling for iOS 10 */ - paper-dialog-scrollable.can-scroll { - --paper-dialog-scrollable: { - -webkit-overflow-scrolling: touch; - } - } - - @media all and (max-width: 450px), all and (max-height: 500px) { - paper-dialog { - margin: 0; - width: 100% !important; - max-height: calc(100% - 64px); - - position: fixed !important; - bottom: 0px; - left: 0px; - right: 0px; - overflow: scroll; - border-bottom-left-radius: 0px; - border-bottom-right-radius: 0px; - } - } -`; +import { haStyle, haStyleDialog } from "./styles"; const documentContainer = document.createElement("template"); documentContainer.setAttribute("style", "display: none;"); @@ -172,6 +79,7 @@ documentContainer.innerHTML = ` --google-blue-500: #4285f4; --google-green-500: #0f9d58; --google-yellow-500: #f4b400; + --paper-spinner-color: var(--primary-color); /* for paper-slider */ --paper-green-400: #66bb6a; @@ -212,6 +120,9 @@ documentContainer.innerHTML = ` --paper-slider-secondary-color: var(--slider-secondary-color); --paper-slider-container-color: var(--slider-bar-color); --ha-paper-slider-pin-font-size: 15px; + + /* mwc */ + --mdc-theme-primary: var(--primary-color); } diff --git a/src/resources/styles.ts b/src/resources/styles.ts new file mode 100644 index 0000000000..66a8b2adc7 --- /dev/null +++ b/src/resources/styles.ts @@ -0,0 +1,88 @@ +import { css } from "lit-element"; + +export const haStyle = css` + :host { + @apply --paper-font-body1; + } + + app-header-layout, + ha-app-layout { + background-color: var(--primary-background-color); + } + + app-header, + app-toolbar { + background-color: var(--primary-color); + font-weight: 400; + color: var(--text-primary-color, white); + } + + app-toolbar ha-menu-button + [main-title], + app-toolbar paper-icon-button + [main-title] { + margin-left: 24px; + } + + h1 { + @apply --paper-font-title; + } + + button.link { + background: none; + color: inherit; + border: none; + padding: 0; + font: inherit; + text-align: left; + text-decoration: underline; + cursor: pointer; + } + + .card-actions a { + text-decoration: none; + } + + .card-actions .warning { + --mdc-theme-primary: var(--google-red-500); + } +`; + +export const haStyleDialog = css` + /* prevent clipping of positioned elements */ + paper-dialog-scrollable { + --paper-dialog-scrollable: { + -webkit-overflow-scrolling: auto; + } + } + + /* force smooth scrolling for iOS 10 */ + paper-dialog-scrollable.can-scroll { + --paper-dialog-scrollable: { + -webkit-overflow-scrolling: touch; + } + } + + .paper-dialog-buttons { + align-items: flex-end; + padding: 8px; + } + + .paper-dialog-buttons .warning { + --mdc-theme-primary: var(--google-red-500); + } + + @media all and (max-width: 450px), all and (max-height: 500px) { + paper-dialog { + margin: 0; + width: 100% !important; + max-height: calc(100% - 64px); + + position: fixed !important; + bottom: 0px; + left: 0px; + right: 0px; + overflow: scroll; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + } + } +`; diff --git a/src/state-summary/state-card-configurator.js b/src/state-summary/state-card-configurator.js index 4b8449ff40..5cc66cf4f5 100644 --- a/src/state-summary/state-card-configurator.js +++ b/src/state-summary/state-card-configurator.js @@ -1,5 +1,5 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import "@polymer/paper-button/paper-button"; +import "@material/mwc-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; @@ -15,9 +15,7 @@ class StateCardConfigurator extends LocalizeMixin(PolymerElement) { return html`